programing

종료는 돌연변이 자체 매개 변수를 암시적으로 캡처할 수 없습니다.

i4 2023. 6. 20. 21:21
반응형

종료는 돌연변이 자체 매개 변수를 암시적으로 캡처할 수 없습니다.

Firebase를 사용하여 이벤트를 관찰한 다음 완료 핸들러 내부에 이미지를 설정하는 중입니다.

FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
        if let _ = snapshot.value as? NSNull {
            self.img = UIImage(named:"Some-image")!
        } else {
            self.img = UIImage(named: "some-other-image")!
        }
})

그러나 이 오류가 발생합니다.

종료는 돌연변이 자체 매개 변수를 암시적으로 캡처할 수 없습니다.

이 오류가 무엇에 대한 것인지 확신할 수 없으며 솔루션을 검색하는 데 도움이 되지 않습니다.

짧은 버전

호출대되유에 대한 하고 있는 FirebaseRef.observeSingleEvent(of:with:)유형일 이 가장 a 값 유 일 높 니 다 습 가 이 성 a 형struct이으로 ?)를 포착하지 못할 수 있습니다.self순식간에@escaping폐회

로 한번 입니다.class).


더 긴 버전

Firebase의 방법은 다음과 같이 선언됩니다.

func observeSingleEvent(of eventType: FIRDataEventType, 
     with block: @escaping (FIRDataSnapshot) -> Void)

block는 감은다같표니다시됩이과로 됩니다.@escaping 수 속성,인 개변 수 속 성 본 함 의 문 에 서 벗 어 날 수 의 하 수 있 미 명 며 도 어 심 지 을 즉 매 음 수 , ▁of ▁lifetime ▁the ▁parameter 수 명 ▁the ▁attribute 도 , ▁escape ▁it ▁which ▁means ▁even ▁and ▁function ▁of 매 ▁mayself(당신의 맥락에서).지식을 는 분석할 수 더 합니다.

struct Foo {
    private func bar(with block: @escaping () -> ()) { block() }

    mutating func bax() {
        bar { print(self) } // this closure may outlive 'self'
        /* error: closure cannot implicitly capture a 
                  mutating self parameter              */
    }
}

이제 오류 메시지가 더욱 명확해지며 Swift 3에 구현된 다음과 같은 진화 제안을 살펴봅니다.

[내 항목 강조] 설명:

캡처inout변환 방법을 포함한 매개 변수는 캡처를 명시적으로(따라서 불변으로) 만들지 않는 한 탈출 가능한 폐쇄 리터럴의 오류가 됩니다.

자, 이것이 핵심 포인트입니다. 유형(예:struct), )에하고 있는 observeSingleEvent(...)이 예제에서는 이러한 명시적 캡처가 불가능합니다. 즉, FAIK입니다(참조가 아닌 값 유형으로 작업하고 있기 때문입니다).

이 문제에 대한 가장 간단한 해결책은 유형을 소유하는 것입니다.observeSingleEvent(...) 예: 조참유예(형: a)class보다는 니▁rather▁a.struct:

class Foo {
    init() {}
    private func bar(with block: @escaping () -> ()) { block() }

    func bax() {
        bar { print(self) }
    }
}

이것이 잡힐 것이라는 것을 조심하세요.self로; (직접 적이 없기 알 수 , 으로 캡처하는 것이 .self약하게, 예를 들어.

FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...

솔루션 동기화

유형을 해야 하는 (" 유형을변하경우는야값해환경(우▁you▁if"struct 동기식으로만 할 수 통화에는 하지 않을 수 만약 당신이 이렇게 쓴다면:

struct Banana {
    var isPeeled = false
    mutating func peel() {
        var result =  self

        SomeService.synchronousClosure { foo in
            result.isPeeled = foo.peelingSuccess
        }

        self = result
    }
}

자아할 수 것은 "mutating self"는 "muting self"는 "mutating self(이 경우 "muting self"는 "muting self"입니다.var .) 복사합니다.

비동기화가 필요한 이유는 무엇입니까?

비동기 컨텍스트에서 이 기능이 작동하지 않는 이유는 다음과 같습니다.result컴파일러 오류 없이, 그러나 당신은 변형된 결과를 다시 할당할 수 없습니다.self오류는 , 그도오없만지겠는류래,만▁still.selfmethod) 되지 않습니다.peel()도 전에 폐쇄가 발송되기도 전에 종료됩니다.

이 문제를 피하기 위해 코드를 변경하여 비동기 호출이 완료될 때까지 기다렸다가 동기 실행으로 변경할 수 있습니다.기술적으로 가능하지만, 이것은 아마도 당신이 상호 작용하고 있는 비동기 API의 목적에 어긋날 것이며, 당신은 당신의 접근 방식을 바꾸는 것이 더 나을 것입니다.

structclass기술적으로 건전한 옵션이지만 실제 문제를 해결하지는 못합니다.예에서, 은 우의예에서은, 금지리.class Banana속성은 who-filen-where를 비동기식으로 변경할 수 있습니다.그것은 이해하기 어렵기 때문에 문제를 일으킬 것입니다.모델 자체 외부에 API 핸들러를 작성하고 실행이 완료되면 모델 개체를 가져오고 변경하는 것이 좋습니다.더 많은 맥락이 없다면, 적절한 예를 들기가 어렵습니다. (모델 코드라고 가정합니다. 왜냐하면self.imgOP의 코드에서 변형되었습니다.)

"비동기식 반부패" 개체를 추가하면 도움이 될 수 있습니다.

저는 이것의 대사 중에서 무엇인가를 생각하고 있습니다.

  • a BananaNetworkRequestHandler합니다.BananaPeelingResult다시 a로 돌아가서BananaStore
  • BananaStore그런 다음 적절한 조치를 취합니다.Banana을 찾아 내부로부터.peelingResult.bananaID
  • 로물를발것견한이 있는 것.banana.bananaID == peelingResult.bananaID그러면 그것은 해가 집니다.banana.isPeeled = peelingResult.isPeeled,
  • 마지막으로 원래 개체를 변환된 인스턴스로 바꿉니다.

특히 필요한 변경 사항에 앱 아키텍처 변경이 포함된 경우 간단한 수정 사항을 찾는 과정에서 쉽게 관여할 수 있습니다.

가 (페이지에 넘어지고 , 당신은 이 페이지를 사용할 수 있습니다.protocol/protocol extension그러면 당신이 선언하는 것이 도움이 될 것입니다.protocol계급에 따라다음과 같이:

protocol MyProtocol: class {
   ...
}

해보세요!도움이 되길 바랍니다.

struct Mutating {
    var name = "Sen Wang"

    mutating func changeName(com : @escaping () -> Void) {

        var muating = self {
            didSet {
                print("didSet")
                self = muating
            }
        }

        execute {
            DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 15, execute: {
                muating.name = "Wang Sen"
                com()
            })
        }
    }

    func execute(with closure: @escaping () -> ()) { closure() }
}


var m = Mutating()
print(m.name) /// Sen Wang

m.changeName {
    print(m.name) /// Wang Sen
}

또 다른 해결책은 자신을 명시적으로 캡처하는 것입니다(나의 경우, 프로토콜 확장의 돌연변이 기능에 있었기 때문에 이것이 참조 유형인지 쉽게 지정할 수 없었습니다).

그래서 이것 대신에:

functionWithClosure(completion: { _ in
    self.property = newValue
})

나는 다음을 가지고 있습니다.

var closureSelf = self
functionWithClosure(completion: { _ in
    closureSelf.property = newValue
})

경고를 잠재운 것 같습니다.

이는 값 유형에 대해서는 작동하지 않으므로 자체가 값 유형인 경우 이 솔루션이 작동하려면 참조 유형 래퍼를 사용해야 합니다.

언급URL : https://stackoverflow.com/questions/41940994/closure-cannot-implicitly-capture-a-mutating-self-parameter

반응형