2016-08-22 4 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 왜냐하면 나는'tableView'에'CIImages'의 메타 데이터를 표시하고 싶고 하나의'tableView.reloadData()'호출로 동기식으로 할 수 있기 때문입니다. –

답변

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

UPDATE 또 하나있다. 주 스레드에서 호출 된 requestContentEditingInputWithOptions의 완료 종료. 즉, 세마포어를 사용하여 주 스레드를 차단하는 경우 완료 폐쇄가 차단 된 상태로 실행됩니다. 차단 된 세마포어 문제를 해결하려면 getCIImages을 메인과 다른 스레드에 호출해야합니다.

어쨌든 비동기적인 것들을 동기식으로 만드는 것은 잘못되었습니다. 당신은 다른 접근 방식을 생각해야합니다.

+2

'지연'이 도입 된 정확한 사례! – Sulthan

+0

없음'guard' 중 하나는'else' 문을 호출하지 않습니다. 이 코드는 내 코드 - 프로그래머 동결 같은 동작을 생성합니다 –

+0

내 대답을 업데이트했습니다 – Silmaril

관련 문제