Andrey M. Andrey M. - 3 months ago 29
Swift Question

Why app is blocked by semaphore?

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.

Answer

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.