2017-04-06 9 views
1

을 isFinished의 등록을 취소하고, 내 대기열에 추가하여 작업을 시작합니다 :때의 <code>isFinished</code> 재산의 KVO 관찰에 등록, 내가 작업 서브 클래스의 인스턴스를 생성, 운영의 KVO 관찰이 간단한 코드 (Xcode를 8.3)에서

class MyOperation : Operation { 
    override func main() { 
     print("starting") 
     print("finishing") 
    } 
} 

class ViewController: UIViewController { 
    let q = OperationQueue() 
    override func viewDidLoad() { 
     super.viewDidLoad() 
     let op = MyOperation() 
     op.addObserver(self, forKeyPath: #keyPath(MyOperation.isFinished), options: [], context: nil) 
     self.q.addOperation(op) 
    } 

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 
     print("Observed \(keyPath)") 
     if let op = object as? Operation { 
      op.removeObserver(self, forKeyPath: #keyPath(MyOperation.isFinished)) 
     } 
    } 
} 

당신이 볼 수 있듯이, 나는 observeValue(forKeyPath...의 구현을 가지고 있으며, 내 계획은 removeObserver(forKeyPath...입니다.

문제는 "키 값 관찰자가 등록되어있는 동안 MyOperation이 할당 취소되었습니다."라는 문제가 앱에 충돌하는 것입니다. 우리는 "시작"과 "마무리"를 인쇄하지만 결코 "관찰 된"인쇄는하지 않습니다. 수술은 전에 존재하지 않는다 나는 내 KVO 알림을 받는다.

이것은 마치 catch 22처럼 보입니다. isFinished을 관찰하여 관찰자를 제거 할 수 없다면 언제해야합니까? [이 문제를 해결하려면 MyOperation에 main의 끝에 KVO 관찰 가능 속성을 추가하면됩니다. 그러나 내가 이것을해야한다는 개념은 매우 이상합니다. 이것이 내가 여기까지 노력하고있어 할 수 있도록 isFinished이 관찰 정확히 왜하지?]

+1

https://developer.apple.com/library/content/technotes/tn2109/_index.html에서 언급 한 문제 일 수 있습니까? - "NSOperation의 isFinished 속성을 관찰하기 위해 KVO (Key-Value Observing)를 사용하면 비슷한 문제가 발생할 수 있습니다 .KVO는 관찰자 또는 관찰자를 보유하지 않지만 사용자가 관찰자를 제거하더라도 -viewWillDisappear : 메서드를 사용하면 KVO 알림이 이미 객체에 표시 될 수 있습니다. 그런 경우 알림을 실행하는 스레드가 할당 취소 된 객체를 호출 할 수 있습니다. " –

+0

@ MartinR이 부분은 '자기'(관찰자)가 존재하지 않을 수도있는 위험에 대해 이야기하고 있으므로 KVO 알림이 존재하지 않는 객체로 전송 될 수 있습니다. 그것은 내 문제의 _opposite_입니다. 내 문제는 내 KVO 알림을 보내지 않고 수술 (observand)이 존재하지 않는다는 것입니다. 'self'는 루트 뷰 컨트롤러이고 어디에도 없습니다. – matt

+0

내가 그것을 시도한 것을 볼 수있는 유용성이 있는가? 'Observed Optional Finishing ("isFinished")'을 끝낼 수 있습니까? 내 응용 프로그램은 * 충돌하지 않습니다 *. 나는 xcode 8.2를 사용하고 있는데, 그게 무슨 뜻인지 이해하기를 바란다. –

답변

2

엑스 코드 8.2에 동일한 주어진 코드를 테스트 한 후에는, 예상대로 콘솔을했다 보여줍니다

starting 
finishing 
Observed Optional("isFinished") 

문제의 이유는 엑스 코드 8.3에서 테스트 것 같다, 아마 그것은 버그 - 또는 그것은 새로운 작동 방식 수정 될 수 있습니다. 그러나 버그로보고하는 것이 좋습니다.

+1

좋아, 그 버그는 코코아 파운데이션 버그가 아니라는 것을 알았습니다 - 이것은'#keyPath'와 관련된 신속한 언어 버그입니다. 해결 방법은'op.addObserver (self, forKeyPath : "isFinished", options : [], context : nil)'대신 리터럴 문자열을 사용하는 것입니다. – matt

+0

다음은 신속한 버그 보고서입니다. https://bugs.swift.org/browse/SR-4397 제출 한 자료가 있지만 (올바르게) 중복 된 것으로 표시되었습니다. – matt

+0

@matt 그러나 이유는 무엇입니까? 우리는 이것을 '#KeyPath (MyOperation.isFinished)'대신 'forKeyPath : "isFinished"로 구현해야합니다. 이 경우는'# selector '로 작업하는 것과 비슷합니다. –

2

Apple이 Swift 3.1 (source)에서 #keyPath 동작을 변경했습니다. 현재 #keyPath(isFinished)"finished"을 반환하고 "isFinished"을 반환했습니다. KVOOperation 클래스를 사용하면 쉽게 혼동 될 수 있으므로 여기에 설명이 나와 있습니다.


당신이 KVO 알림 객체를 등록

textView.addObserver(self, 
        forKeyPath: #keyPath(UITextView.isEditable), 
        options: [.new, .old], 
        context: nil) 

재단은 willChangeValue(forKey:)didChangeValue(forKey:) (this is done via isa-swizzling)를 호출 새로운 세터 구현으로 (textView)를 제공합니다. 이러한 메서드에 전달되는 키는 getter (isEditable)가 아니고 (setEditable:) 속성 이름 (editable)이 아닙니다. 이 #keyPath(UITextView.isEditable)에서 editable을받을 것으로 예상되는 이유

@property(nonatomic,getter=isEditable) BOOL editable 

이다.


조작 클래스가 속성 정의 광고가

@property (readonly, getter=isExecuting) BOOL executing; 
@property (readonly, getter=isFinished) BOOL finished; 

그것은 isFinishedisExecuting 키에 대한 알림을 관찰 할 것으로 예상 다음 있지만

.

완료 또는 작업의 취소시

, 당신의 동시 작업 개체는 조작을위한 국가의 최종 변화를 표시하는 키 경로를 isExecuting 모두 KVO 알림을 생성하고 isFinished해야한다 이것은 우리를 강제

이러한 알림을 게시 할 때 리터럴 문자열을 사용하십시오.

이건 실수입니다. 기존 코드를 손상시키지 않고 복구하기가 정말 어렵습니다.

+0

예, 모든 것을 알고 있습니다. – matt