【问题标题】:Photos Framework. requestImageForAsset returning two results. Can't set image view照片框架。 requestImageForAsset 返回两个结果。无法设置图像视图
【发布时间】:2015-02-24 13:04:25
【问题描述】:

所以我使用 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)

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

谢谢。

【问题讨论】:

  • 你解决了吗?
  • 使用options.isSynchronous = true

标签: ios uiimageview uicollectionview photosframework


【解决方案1】:

查看 Apple 文档以了解此方法 here. 他们说:

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

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

【讨论】:

    【解决方案2】:

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

    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)
                    }
                })
    

    【讨论】:

    • uhhh,那种解决方案是一个非常不可靠的黑客,请参阅接受的答案以获得一个好的方法
    【解决方案3】:

    读取PHImageManager类的头部

    如果 -[PHImageRequestOptions isSynchronous] 返回 NO(或 options 是 nil),resultHandler 可能会被调用 1 次或多次。通常在这个 情况下,resultHandler 将在主线程上被异步调用 与要求的结果。但是,如果 deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic, resultHandler 可能是 如果有任何图像数据,则在调用线程上同步调用 立即可用。如果第一遍返回的图像数据 质量不够,resultHandler会被再次调用, 稍后使用“正确”在主线程上异步 结果。如果请求被取消,resultHandler 可能不会被调用 一点也不。如果 -[PHImageRequestOptions isSynchronous] 返回 YES, resultHandler 将被同步调用一次,并且在 调用线程。无法取消同步请求。 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
    }];
    

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

    祝你好运!

    【讨论】:

    • 我认为 VietHung 的答案是正确的。要强制返回全分辨率图像,请选择同步选项。否则,您可以保留代码原样并首先显示低分辨率缩略图,然后允许第二次调用该块以更新图像视图中的图像。这很可能是 Apple 选择在主线程上执行回调的原因,这样您就可以在完整的 res 图像可用后进行任何您想要的更新。
    • 如果你选择后者,也许在块中的 imageView 上调用 setNeedsDisplay 看看会发生什么。
    • 这正是我想要的。超级:)
    • 不错!很好的解释。
    • 谢谢。很好的解释。
    【解决方案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

    【讨论】:

      【解决方案5】:

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

      文档是这样说的:

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

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

      【讨论】:

      • 在这种情况下,键 PHImageResultIsDegradedKey 的值为 false
      【解决方案6】:

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

      [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:target contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
          if ([info objectForKey:@"PHImageFileURLKey"]) {
            //your code
          }
      }];
      

      【讨论】:

        【解决方案7】:

        使用以下选项,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}
        

        【讨论】:

          【解决方案8】:

          这是我应用过的最好的解决方案,而且效果很好

          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
                      
                  }
              })
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-09-11
            • 2015-01-30
            • 2015-11-26
            • 1970-01-01
            相关资源
            最近更新 更多