PHContentEditingInputRequestOptions的EXIF块主线程

问题描述 投票:1回答:2

我越来越像EXIFS为了获得LensMake。

这是我发现做到这一点的唯一方法:

let lstAssets : PHFetchResult<PHAsset> = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: nil)
lstAssets.enumerateObjects({object , index, stop in
    let options = PHContentEditingInputRequestOptions()
    object.requestContentEditingInput(with: options) { (contentEditingInput: PHContentEditingInput?, _) -> Void in
        let fullImage : CIImage = CIImage(contentsOf: contentEditingInput!.fullSizeImageURL!)!
        if let exif = fullImage.properties["{Exif}"]{ ...

的问题是,在requestContentEditingInput的回调/ clasure /完成的代码在主线程上运行,并阻止从UI任何呼叫(例如IBAction为一个按钮)。所以,如果我开始的100 lstAssets.count并在enumerateObjects 100个请求,所有的回调需要完成,执行该UI的东西。

我尝试没有成功放置enumerateObjects在DispatchQueue.global(QOS:系统技术领域).async。同样的情况,如果我把回调代码在后台线程。

奇怪的是,这种行为是不同的,如果我有PHImageManager.default()与requestImageData的图像,但问题是,我不能让EXIF的方式。

如何疏通队列?有没有更好的方式来获得EXIF?

我在Xcode 8.2运行斯威夫特3。

更新:通过GCD怪异的行为:在PHContentEditingInputRequestOptions前右运行requestImageData权enumerateObjects内疏导为主线,但仍然可以通过点击获取到下一个屏幕时UI等待回调结束。

ios swift multithreading grand-central-dispatch exif
2个回答
4
投票

如果你只需要读取你可以使用PHImageManager这与后台队列友好的EXIF元数据。所以,你可以更改您的代码是这样的:

let operationQueue = OperationQueue()

let lstAssets : PHFetchResult<PHAsset> = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: nil)
operationQueue.addOperation {
    self.readPhotosMetadata(result: lstAssets, operationQueue: operationQueue)
}

func readPhotosMetadata(result: PHFetchResult<PHAsset>, operationQueue: OperationQueue) {
    let imageManager = PHImageManager.default()
    result.enumerateObjects({object , index, stop in
        let options = PHImageRequestOptions()
        options.isNetworkAccessAllowed = true
        options.isSynchronous = false
        imageManager.requestImageData(for: object, options: options, resultHandler: { (imageData, dataUTI, orientation, info) in
            operationQueue.addOperation {
                guard let data = imageData,
                    let metadata = type(of: self).fetchPhotoMetadata(data: data) else {
                        print("metadata not found for \(object)")
                        return
                }
                print(metadata)
            }
        })
    })
}

static func fetchPhotoMetadata(data: Data) -> [String: Any]? {
    guard let selectedImageSourceRef = CGImageSourceCreateWithData(data as CFData, nil),
        let imagePropertiesDictionary = CGImageSourceCopyPropertiesAtIndex(selectedImageSourceRef, 0, nil) as? [String: Any] else {
        return nil
    }
    return imagePropertiesDictionary

}

0
投票

我们可以通过更少的代码和更快的从这样的图像读取的Exif:

let firstAsset = PHAsset.fetchAssets(with: .image, options: nil).firstObject!
// For example I've used first PHAsset

firstAsset.requestContentEditingInput(with: PHContentEditingInputRequestOptions()) { (eidtingInput, info) in
                if let input = eidtingInput, let imgURL = input.fullSizeImageURL {
                    let img = CIImage(contentsOf: imgURL)!
                    let imgPro = img.properties
                    let exifDic = imgPro["{Exif}"] as! NSDictionary
                    print(exifDic)
                  }
               }
© www.soinside.com 2019 - 2024. All rights reserved.