为什么应用程序被信号量阻止?

时间:2016-08-22 10:42:52

标签: ios swift grand-central-dispatch semaphore phasset

我有以下函数,假设为了我的目的返回[CIImage] - 在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
}

但是它停留在信号量等待中并且没有进一步发展。我已经浏览了很多教程,但GCD的其他变种不起作用。我认为这是因为模拟器,我不知道,无法在真实设备上进行测试。请帮忙。

1 个答案:

答案 0 :(得分:5)

内部requestContentEditingInputWithOptions回调闭包中的警卫会阻止信号发送到信号量。 在这种情况下(当您需要清理操作时),最好使用defer。在你的情况下:

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)
}

<强>更新

除了清理bug之外还有另一个。在主线程上调用requestContentEditingInputWithOptions的完成关闭。这意味着如果使用信号量阻塞主线程:完成闭包也会被阻止执行。要修复阻塞的信号量问题,您需要在与主要不同的线程上调用getCIImages

无论如何使异步事物同步是错误的。你应该想到不同的方法。