I have the following function that suppose to return [CIImage]
for my purpose - displaying some metadata of photos in tableView.
func getCIImages() -> [CIImage] {
var images = [CIImage]()
let assets = PHAsset.fetchAssetsWithMediaType(.Image, options: nil)
for i in 0..<assets.count {
guard let asset = assets[i] as? PHAsset else {fatalError("Cannot cast as PHAsset")}
let semaphore = dispatch_semaphore_create(0)
asset.requestContentEditingInputWithOptions(nil) { contentEditingInput, _ in
//Get full image
guard let url = contentEditingInput?.fullSizeImageURL else {return}
guard let inputImage = CIImage(contentsOfURL: url) else {return}
images.append(inputImage)
dispatch_semaphore_signal(semaphore)
}
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}
return images
}
but it stucks in semaphore wait and didn't go further. I have walked through many tutorials but other variants of GCD don't works. I think it's because of simulator, I don't know, can't test on real device. Please help.
guards inside requestContentEditingInputWithOptions
callback closure prevents signal sent to semaphore.
In such cases (when you need cleanup actions) it is good to use defer. In your case:
asset.requestContentEditingInputWithOptions(nil) { contentEditingInput, _ in
defer { dispatch_semaphore_signal(semaphore) }
//Get full image
guard let url = contentEditingInput?.fullSizeImageURL else {return}
guard let inputImage = CIImage(contentsOfURL: url) else {return}
images.append(inputImage)
}
UPDATE
Apart from cleanup bug there is another one. Completion closure of requestContentEditingInputWithOptions
called on main thread. Which means that if you blocking main thread with semaphore: completion closure is blocked form executing as well. To fix blocked semaphore issue you need call getCIImages
on a different thread than main.
Anyway making asynchronous things synchronous is wrong. You should think of different approach.