【问题标题】:Swift 4 completion handler for loop not working用于循环的 Swift 4 完成处理程序不起作用
【发布时间】:2019-03-05 22:09:07
【问题描述】:

在 swift 4 中,我有一个使用完成处理程序执行循环的方法:

func loopImages(qa: QAClass, assets: [DKAsset], completion: ([PhotoClass]) -> Void) {

        var imageCellHolder = [PhotoClass]()

            for x in assets
            {

                x.fetchOriginalImage(completeBlock: { (image, info) in

                     let compressedImage = image?.resizeWithWidth(width: 800)

                     let imageData:Data = compressedImage!.jpegData(compressionQuality: 0.5)!

                     imageCellHolder.append(PhotoClass(job: String(self.selectedCommunity! + self.selectedLot!), photo: imageData, itemId: qa.itemId))

                 })
            }

            completion(imageCellHolder)        
    }

这是它假设在循环完成时调用的方法:

func loopFinished(imageCellHolder: [PhotoClass])
    {
        self.saveQAPhotos(cellHolder: imageCellHolder) { result in

            print(result)

        }
    }

这就是我调用循环方法的方式:

self.loopImages(qa: qa, assets: assets, completion: self.loopFinished)

我的问题是在循环完成之前调用了完成处理程序方法(loopFinished)。

如果您想知道,fetchOriginalImage 来自库 DKImagePickerController https://github.com/zhangao0086/DKImagePickerController

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    你需要一个DispatchGroup 来完成多个不定时任务

    func loopImages(qa: QAClass, assets: [DKAsset], completion: ([PhotoClass]) -> Void) {
    
        var imageCellHolder = [PhotoClass]()
    
        let dispa = DispatchGroup()
    
        for x in assets
        {
            dispa.enter()
    
            x.fetchOriginalImage(completeBlock: { (image, info) in
    
                let compressedImage = image?.resizeWithWidth(width: 800)
    
                let imageData:Data = compressedImage!.jpegData(compressionQuality: 0.5)!
    
                imageCellHolder.append(PhotoClass(job: String(self.selectedCommunity! + self.selectedLot!), photo: imageData, itemId: qa.itemId))
    
                dispa.leave()
    
            })
        }
    
        dispa.notify(queue: .main) {
             completion(imageCellHolder)
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      这样做的原因是获取图像需要时间,实际的 for 循环完成非常快并返回一个空数组,因为尚未获取图像。

      考虑使用DispatchGroup

      func loopImages(qa: QAClass, assets: [DKAsset], completion: ([PhotoClass]) -> Void) {
      
          var imageCellHolder = [PhotoClass]()
          let group = DispatchGroup()
      
          for x in assets
          {
              group.enter()
              x.fetchOriginalImage(completeBlock: { (image, info) in
      
                  let compressedImage = image?.resizeWithWidth(width: 800)
      
                  let imageData:Data = compressedImage!.jpegData(compressionQuality: 0.5)!
      
                  imageCellHolder.append(PhotoClass(job: String(self.selectedCommunity! + self.selectedLot!), photo: imageData, itemId: qa.itemId))
                  group.leave()
      
              })
      
              group.notify(queue: .main) {
                  completion(imageCellHolder)
              }
          }
      }
      

      DispatchGroup 将等待所有图像完成下载,并在完成时调用完成

      【讨论】:

        【解决方案3】:

        您的任务是异步的。这意味着,您在请求数据后不会立即获得数据。您需要等待,然后获取每张图片。

        您可以避免使用DispatchGroup,并且可以通过增加一些计数变量来跟踪是否已获取每个图像。在获取的图像计数与assets 数组的计数相同后,您可以调用completion

        func loopImages(qa: QAClass, assets: [DKAsset], completion: ([PhotoClass]) -> Void) {
        
            var imageCellHolder = [PhotoClass]()
        
            var count = 0 // <--
        
            for x in assets {
        
                x.fetchOriginalImage { image, info in
        
                    let compressedImage = image?.resizeWithWidth(width: 800)
        
                    let imageData:Data = compressedImage!.jpegData(compressionQuality: 0.5)!
        
                    imageCellHolder.append(PhotoClass(job: String(self.selectedCommunity! + self.selectedLot!), photo: imageData, itemId: qa.itemId))
        
          /* -> */  count += 1
                    if count == assets.count {
                        completion(imageCellHolder)
                    }
        
                }
            }
        
        }
        

        【讨论】:

          【解决方案4】:

          这是因为 fetchOriginalImage 是异步的,您应该使用 DispatchGroup 之类的东西来跟踪所有异步调用何时完成

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-03-21
            • 1970-01-01
            相关资源
            最近更新 更多