0

백그라운드 스레드에서 실행되는 블록으로 구성된 계산 된 속성을 선언하려고합니다. 그래서이 속성을 처리 할 때는 준비가되지 않았을 때 계산 결과가 반환되므로 nil입니다. 이 문제를 어떻게 해결할 수 있을까요? 고맙습니다!계산에서 백그라운드 스레드를 사용할 때 계산 된 속성을 올바르게 선언하는 방법은 무엇입니까?

enum Result<T> { 
    case error(error: Error) 
    case success(data: T) 
} 

var userID: Result<CKRecordID>? { 

    var result: Result<CKRecordID>? = nil 

    container.fetchUserRecordID { recordID, error in 
    if let error = error { result = .error(error: error) } 
    if let recordID = recordID { result = .success(data: recordID) } 
    } 

    return result 
} 
+0

대신 폐쇄를 사용할 수 없습니다. 그래서 fetch 사용자가 돌아 오면 completed() 클로저를 실행하고 레코드 ID를 반환하겠습니까? – arvidurs

+0

속성에서 비동기 적으로 값을 반환 할 수 없습니다. –

+5

이론적으로 응답을 기다리는 패턴을 적용 할 수 있지만 비동기 검색 메커니즘의 전체 개념은 응답을 기다리는 주 스레드를 차단하지 않도록하는 것입니다. 따라서 간단한 대답은 비동기 메서드를 래핑하기 위해 실제로 계산 된 속성을 사용하지 말아야한다는 것입니다. 그냥'fetchUserRecordID'를 고수하십시오. 완료 핸들러 클로저에서'Result '타입을 반환하는 어떤 방법으로 그것을 감싸고 싶다면, 괜찮지 만 계산 된 속성으로 처리하려고하지 마십시오. – Rob

답변

1

GCD 세마포어를 사용하는 것과 같은 간단한 해결책이 있습니다. 그러나 전체 접근법은 처음에는 올바르지 않은 것처럼 보입니다. 일부 상황 (예 : 메인 스레드에서이 속성을 호출하는 경우)에서 원하지 않는 중단 또는 교착 상태가 발생할 수 있습니다. 더 나은 접근법은 코드를 적절한 완료 핸들러가있는 메소드로 옮기는 것입니다.

계산 된 속성은 메서드를 대체하기위한 것이 아닙니다. 범위에 복잡한 (특히 비동기) 계산이있는 경우 해당 코드를 속성에서 메서드로 옮길 수 있습니다.

어쨌든 : 여기

var userID: Result<CKRecordID>? { 

    var result: Result<CKRecordID>? = nil 

    var sema = DispatchSemaphore(value: 0) 

    container.fetchUserRecordID { recordID, error in 
     if let error = error { result = .error(error: error) } 
     if let recordID = recordID { result = .success(data: recordID) } 

     sema.signal() 
    } 

    _ = sema.wait(timeout: .distantFuture) 

    return result 
} 

당신은 비동기 작업이 완료 될 때까지 기다립니다 GCD 세마포어가 있습니다.

관련 문제