iOS - 从设备中获取所有照片并将其保存到应用程序

时间:2016-04-27 14:11:49

标签: ios swift memory phasset photosframework

我想获取设备中保存的所有照片并将其保存到我的应用中,然后最终(如果用户允许)删除原件。

这是我为此任务创建的全班课程:

class ImageAssetsManager: NSObject {
  let imageManager = PHCachingImageManager()

  func fetchAllImages() {
    let options = PHFetchOptions()
    options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.Image.rawValue)
    options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
    if #available(iOS 9.0, *) {
      options.fetchLimit = 5
    } else {
      // Fallback on earlier versions
    }

    let imageAssets = PHAsset.fetchAssetsWithOptions(options)
    print(imageAssets.count)
    self.getAssets(imageAssets)
  }

  func getAssets(assets: PHFetchResult) {
    var assetsToDelete: [PHAsset] = []

    assets.enumerateObjectsUsingBlock { (object, count, stop) in
      if object is PHAsset {
        let asset = object as! PHAsset
        let imageSize = CGSize(width: asset.pixelWidth,height: asset.pixelHeight)

        let options = PHImageRequestOptions()
        options.deliveryMode = .FastFormat
        options.synchronous = true

        self.imageManager.requestImageForAsset(asset, targetSize: imageSize, contentMode: .AspectFill, options: options, resultHandler: { [weak self]
          image, info in

          self.addAssetToSync(image, info: info)
          assetsToDelete.append(asset)
          })
      }
    }
    self.deleteAssets(assetsToDelete)
  }

  func addAssetToSync(image: UIImage?, info: [NSObject : AnyObject]?) {
    guard let image = image else {
      return
    }

    guard let info = info else {
      return
    }
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
      let imageData = UIImageJPEGRepresentation(image, 0.95)!
      let fileUrl = info["PHImageFileURLKey"] as! NSURL

      dispatch_async(dispatch_get_main_queue(), {
        let photoRootItem = DatabaseManager.sharedInstance.getPhotosRootItem()
        let ssid = DatabaseManager.sharedInstance.getSsidInfoByName(ContentManager.sharedInstance.ssid)
        let item = StorageManager.sharedInstance.createFile(imageData, name: fileUrl.absoluteString.fileNameWithoutPath(), parentFolder: photoRootItem!, ssid: ssid!)
      })
    })
  }

  func deleteAssets(assetsToDelete: [PHAsset]){
    PHPhotoLibrary.sharedPhotoLibrary().performChanges({
      PHAssetChangeRequest.deleteAssets(assetsToDelete)
      }, completionHandler: { success, error in
        guard let error = error else {return}
    })
  }
}

它正在运作但我的问题是它只适用于有限数量的照片。当我尝试所有我得到内存警告然后应用程序崩溃。我知道它为什么。我知道我的问题是我把所有照片都记在了内存中,这太过分了。我可以获取具有该获取限制的图像并使其循环但我不确定它是否是最佳解决方案。

我希望通过一些解决方案处理几张照片然后一次又一次地释放记忆直到结束。但是这个改变将在enumerateObjectsUsingBlock中的某个地方。我不确定它是否有帮助,但我甚至不需要获取图像。我只需要将图像文件从设备路径复制到我的应用程序沙箱路径。

对此最好的解决方案是什么?如何避免内存警告和泄漏?感谢

1 个答案:

答案 0 :(得分:0)

将dispatch_async调用更改为dispatch_sync。然后,当您浏览enumerateObjectsUsingBlock时,您将逐个处理一张照片,而不是尝试同时处理它们。