2016-08-22 19 views
-1

私は、目的のために[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の他のバリエーションはうまくいきません。私はそれがシミュレータのためだと思う、私は知らない、実際のデバイスでテストすることはできません。助けてください。

+2

なぜ擬似同期リクエストを強制的に強制しますか? – vadian

+0

@vadian私は 'CIImages'のいくつかのメタデータを' tableView'に表示したいので、 'tableView.reloadData()'呼び出しを使って同期的に行うことができます。 –

答えて

5

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

UPDATE

別にクリーンアップバグから別のものがあります。メインスレッドで呼び出されたrequestContentEditingInputWithOptionsの完了クロージャ。つまり、セマフォーでメインスレッドをブロックすると、完了クロージャはブロックされ、フォームも実行されます。ブロックされたセマフォの問題を修正するには、getCIImagesをメインとは別のスレッドで呼び出す必要があります。

とにかく非同期のものを同期させるのは間違っています。あなたは異なったアプローチを考えるべきです。

+2

'defer'が導入されたのはまさにそのケースです! – Sulthan

+0

なし 'guard'のいずれかが' else'ステートメントを呼び出しません。このコードは、私のコードのような同じ振る舞いを生成します - プログラムフリーズ –

+0

私の答えを更新しました – Silmaril

関連する問題