code

비탈출 매개변수를 폐쇄적으로 사용하면 탈출할 수 있습니다.

starcafe 2023. 6. 17. 09:32
반응형

비탈출 매개변수를 폐쇄적으로 사용하면 탈출할 수 있습니다.

프로토콜이 있습니다.

enum DataFetchResult {
    case success(data: Data)
    case failure
}

protocol DataServiceType {
    func fetchData(location: String, completion: (DataFetchResult) -> (Void))
    func cachedData(location: String) -> Data?
}

구현 예를 사용하여:

    /// An implementation of DataServiceType protocol returning predefined results using arbitrary queue for asynchronyous mechanisms.
    /// Dedicated to be used in various tests (Unit Tests).
    class DataMockService: DataServiceType {

        var result      : DataFetchResult
        var async       : Bool = true
        var queue       : DispatchQueue = DispatchQueue.global(qos: .background)
        var cachedData  : Data? = nil

        init(result : DataFetchResult) {
            self.result = result
        }

        func cachedData(location: String) -> Data? {
            switch self.result {
            case .success(let data):
                return data
            default:
                return nil
            }
        }

        func fetchData(location: String, completion: (DataFetchResult) -> (Void)) {

            // Returning result on arbitrary queue should be tested,
            // so we can check if client can work with any (even worse) implementation:

            if async == true {
                queue.async { [weak self ] in
                    guard let weakSelf = self else { return }

                    // This line produces compiler error: 
                    // "Closure use of non-escaping parameter 'completion' may allow it to escape"
                    completion(weakSelf.result)
                }
            } else {
               completion(self.result)
            }
        }
    }

위의 코드는 Swift3(Xcode8-beta5)에서 컴파일되어 작동했지만 베타 6에서는 더 이상 작동하지 않습니다.근본적인 원인을 말씀해 주시겠습니까?

이는 함수 유형의 매개 변수에 대한 기본 동작이 변경되었기 때문입니다.Swift 3(특히 Xcode 8 베타 6과 함께 제공되는 빌드) 이전에는 기본적으로 이스케이프 상태가 됩니다. 이를 표시해야 합니다.@noescape저장되거나 캡처되는 것을 방지하기 위해 기능 호출 기간보다 오래 지속되지 않도록 보장합니다.

하지만, 지금은@noescape는 함수 계산 매개 변수의 기본값입니다.이러한 기능을 저장하거나 캡처하려면 이제 해당 기능을 표시해야 합니다.@escaping:

protocol DataServiceType {
  func fetchData(location: String, completion: @escaping (DataFetchResult) -> Void)
  func cachedData(location: String) -> Data?
}

func fetchData(location: String, completion: @escaping (DataFetchResult) -> Void) {
  // ...
}

이 변경에 대한 자세한 내용은 Swift Evolution 제안서를 참조하십시오.

@noescape가 기본이므로 오류를 수정하는 두 가지 옵션이 있습니다.

@Hamish가 그의 대답에서 지적했듯이, 만약 당신이 결과에 관심이 있고 정말로 그것이 탈출하기를 원한다면, 단지 완료를 @escape로 표시하세요 (그것은 아마도 유닛 테스트와 비동기 완료의 가능성을 가진 @Lukasz의 질문의 경우일 것입니다).

func fetchData(location: String, completion: @escaping (DataFetchResult) -> Void)

OR

결과에 관심이 없는 경우 완료 옵션을 선택하여 결과를 모두 삭제함으로써 기본 @noescape 동작을 유지합니다.예를 들어 사용자가 이미 "떠났"고 콜링 뷰 컨트롤러가 부주의한 네트워크 호출이 있었다고 해서 메모리에 남아 있을 필요가 없는 경우입니다.제가 답을 찾으러 왔을 때와 마찬가지로 샘플 코드는 저와 별로 관련이 없었기 때문에 @noescape를 표시하는 것은 처음에는 유일한 것처럼 들렸지만 최선의 선택은 아니었습니다.

func fetchData(location: String, completion: ((DataFetchResult) -> Void)?) {
   ...
   completion?(self.result)
}

완료 블록 만들기:optional변수는 스위프트 5의 문제를 해결하는 데 도움이 되었습니다.

 private func updateBreakTime(for id: String, to time: Time, onSucess: EmptyAction?) {
    dataRepository.updateBreak(
        id: id,
        to: time.seconds,
        onSuccess: { _ in
            onSucess?()
        },
        onError: { [weak self] error in
            self?.screen.showError(error)
        }
    )
}

데이터 저장소의 성공 여부@escaping

언급URL : https://stackoverflow.com/questions/38990882/closure-use-of-non-escaping-parameter-may-allow-it-to-escape

반응형