26

所以我使用 SwipeView 库 ( https://github.com/nicklockwood/SwipeView ) 来使用 iOS8 的照片框架显示图像。

但是,当我调用 requestImageForAsset 时,我注意到我得到了两个结果,一个是缩略图大小,另一个是我想要的更大的大小。但是,较大的图像没有及时加载(我理解它被称为异步)返回,所以它返回了小图像。

这段代码可能更有意义。

    func swipeView(swipeView: SwipeView!, viewForItemAtIndex index: Int, reusingView view: UIView!) -> UIView! {
            let asset: PHAsset = self.photosAsset[index] as PHAsset

    var imageView: UIImageView!

    let screenSize: CGSize = UIScreen.mainScreen().bounds.size
    let targetSize = CGSizeMake(screenSize.width, screenSize.height)


    var options = PHImageRequestOptions()
//        options.deliveryMode = PHImageRequestOptionsDeliveryMode.Opportunistic
    options.resizeMode = PHImageRequestOptionsResizeMode.Exact


    PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options, resultHandler: {(result, info)in
        println("huhuhuh")
        println(result.size)
        println(info)
        imageView = UIImageView(image: result)
    })
    println("setting view)
    return imageView
}

这是日志输出:

Enteredhuhuhuh
(33.5,60.0)
SETTING VIEW
huhuhuh
(320.0,568.0)

如您所见,它在接收到大图像之前返回图像视图。如何让它返回这个更大的图像,所以它不显示缩略图?

谢谢。

4

8 回答 8

91

读取PHImageManager类的标题

如果 -[PHImageRequestOptions isSynchronous] 返回 NO(或 options 为 nil),resultHandler 可能会被调用 1 次或多次。通常在这种情况下,resultHandler 将在主线程上异步调用请求的结果。但是,如果deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic,如果任何图像数据立即可用,则可以在调用线程上同步调用resultHandler。如果第一次返回的图像数据质量不足,resultHandler 将在稍后在主线程上再次异步调用,并提供“正确”的结果。如果请求被取消,resultHandler 可能根本不会被调用。如果 -[PHImageRequestOptions isSynchronous] 返回 YES,resultHandler 将在调用线程上同步调用一次。无法取消同步请求。

所以,你想做的是让你resultHandler被称为synchronously

PHImageRequestOptions *option = [PHImageRequestOptions new];
option.synchronous = YES;

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:target contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
        //this block will be called synchronously
}];

所以你的块将在结束你的方法之前被调用

祝你好运!

于 2014-12-30T07:00:48.397 回答
4

默认情况下,requestImageForAsset工作是异步的。因此,在您的方法中,即使在检索图像之前,也会执行 return 语句。所以我的建议不是返回 imageView,而是传递你需要填充图像的 imageView:

func swipeView(swipeView: SwipeView!, viewForItemAtIndex index: Int, reusingView view: UIView!, yourImageView: UIImageView)
{
    let asset: PHAsset = self.photosAsset[index] as PHAsset

    var imageView: UIImageView! = yourImageView;

    let screenSize: CGSize = UIScreen.mainScreen().bounds.size
    let targetSize = CGSizeMake(screenSize.width, screenSize.height)


    var options = PHImageRequestOptions()
    options.resizeMode = PHImageRequestOptionsResizeMode.Exact

    PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options, resultHandler: {(result, info)in
        imageView.image = result;
    })
}

笔记:

另一种选择是您可以使用来自 resultHandler 的结果图像触发通知。但我更喜欢上面提到的方法。

请参阅PHImageManager了解更多信息。

于 2014-12-30T07:01:41.930 回答
4

resultHandler:块具有信息字典,其中可能包含键的布尔值PHImageResultIsDegradedKey,指示结果图像是否是请求图像的低质量替代品。

这是文档中的内容:

PHImageResultIsDegradedKey:一个布尔值,指示结果图像是否是请求图像的低质量替代品。(NSNumber)

如果是,则 resultHandler 块的结果参数包含低质量图像,因为照片还不能提供更高质量的图像。根据您随请求提供的 PHImageRequestOptions 对象中的设置,Photos 可能会再次调用您的结果处理程序块以提供更高质量的图像。

于 2015-10-07T18:04:50.410 回答
2

您不应该在块内重写 imageView,只需将 image 设置为它,一切都应该按您的预期工作。为了避免显示两个图像,您可以在分配之前检查图像的大小。

var imageView =  UIImageView()
...
...
        PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options, resultHandler: {(result, info)in
                println("huhuhuh")
                println(result.size)
                println(info)
                if result.size.width > 1000 &&  result.size.height > 1000 { // add any size you want 
                     imageView.setImage(result)
                }
            })
于 2014-12-30T06:41:47.290 回答
1

在此处查看此方法的 Apple 文档他们在说:

对于异步请求,照片可能会多次调用您的结果处理程序块。照片首先调用该块以提供适合临时显示的低质量图像,同时准备高质量图像。(如果低质量的图像数据立即可用,则第一次调用可能发生在方法返回之前。)

在您的情况下,获取原始大小的图像可能需要一些时间。否则你的代码对我来说似乎没问题。

于 2014-12-30T06:15:03.590 回答
0

使用以下选项,swift 3.0

publi var imageRequestOptions: PHImageRequestOptions{
let options = PHImageRequestOptions()
options.version = .current
options.resizeMode = .exact
options.deliveryMode = .highQualityFormat
options.isNetworkAccessAllowed = true
options.isSynchronous = true
return options}
于 2017-02-08T09:29:19.340 回答
0

试试这个也可以异步工作。

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:target contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
    if ([info objectForKey:@"PHImageFileURLKey"]) {
      //your code
    }
}];
于 2017-02-07T09:22:13.633 回答
0

这是我应用的最佳解决方案,并且运行良好

let imageManager = PHImageManager.default()
        let requestOptions = PHImageRequestOptions()
    requestOptions.deliveryMode =  .highQualityFormat
    requestOptions.version = .current
    requestOptions.resizeMode = .exact
    requestOptions.isSynchronous = true

    imageManager.requestImage(for: self.assets.first!, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: nil, resultHandler: { image, info in
        if let info = info, info["PHImageFileUTIKey"] == nil {
            if let isDegraded = info[PHImageResultIsDegradedKey] as? Bool, isDegraded {
                //Here is Low quality image , in this case return
                print("PHImageResultIsDegradedKey =======> \(isDegraded)")
                return
            }
            //Here you got high resilutions image
            
        }
    })
于 2020-10-02T09:08:11.137 回答