2017-01-10 7 views
0

값이 참조 유형 일 때 NSUndoManager가 값을 캡처하는 방법을 이해하는 데 문제가 있습니다. undoManager를 사용하려고 할 때마다 값은 실행 취소되지 않습니다.NSUndoManager : 참조 유형 캡처 가능?

참고 : 나는 맥 OS 10.10 지원해야, 난, -1로 그들 모두를 다시 나는 ID 번호의 상태를 저장 스위프트 3, 엑스 코드 (8) 여기

를 사용하여 다음 취소하려고하고 있습니다. 결과는 모두 여전히 -1입니다.

import Cocoa 

class Person: NSObject { 
    var id: ID 
    init(withIDNumber idNumber: Int) { 
     self.id = ID(idNumber) 
    } 
}  

class ID: NSObject { 
    var number: Int 
    init(_ number: Int) { 
     self.number = number 
    } 
} 

ViewController... { 

    @IBAction func setIDsToNegative1(_ sender: NSButton) { 
     var savedIDs: [ID] = [] 
     for person in people { 
      savedIDs.append(person.id) 
     } 

     undoManager?.registerUndo(withTarget: self, selector:#selector(undo(savedIDs:)), object: savedIDs) 

     for person in people { 
      person.id.number = -1 
     } 
    } 


    func undo(savedIDs: [ID]) { 
     for id in savedIDs { 
       print(id.number) 
     } 
     //Prints -1, -1, -1 
    } 

} 

ID 개체를 저장하는 대신 값을 캡처하는 것이 문제라는 것을 증명하기 위해 포함 된 Int 값을 저장했습니다. Ints가 값 유형이므로 완벽하게 작동했습니다.

그런 다음 클로저 캡처에 대해 좀 더 읽고이를 시도했습니다.

undoManager?.registerUndo(withTarget: self, handler: { [saved = savedIDs] 
    (self) ->() in 
     self.undo(savedIDs: saved) 
}) 

같은 문제는 모두 여전히 -1입니다.

답변

1

NSUndoManager는 오래된 에 대해 캡처에 대해 있지만 원래 값을 복원 작업을 캡처에 대해 정말 아니다.

ID에 대한 참조 만 캡처하고 있습니다. 따라서 savedIDs의 요소는 people 요소의 id 속성과 동일한 개체를 가리 킵니다. 즉, 요소를 변경하면 다른 요소도 변경됩니다.

수동 그렇게처럼 ID의 당신은으로 재설정 할 값을 저장하기 만하면 무엇 :

let savedPairs = people.map { (id: $0.id, originalValue: $0.id.number) } 

idnumber 값 자체가 어딘가에뿐만 아니라 저장되는 것을 보장한다 id에 대한 포인터

그런 다음, 수동 촬영 한 값으로 파멸을 수행하므로 같은 작업 등록 할 수 있습니다 :

undoManager.registerUndo(withTarget: self) { 
    savedPairs.forEach { $0.id.number = $0.originalValue } 
} 
+0

덕분에, 이것은 내가 "동결 건조"참조 상태가 불가능하다고하지만 의심 것을 확인 . 제공된 예제에서는 데이터 구조가 매우 간단하여 튜플을 절약하는 것이 쉽습니다. 하지만 다른 참조 유형으로 구성된 훨씬 복잡한 데이터 구조를 가진 클래스를 실행 취소하려면 어떻게해야합니까? 객체 구조를 자세히 조사하고 모든 값 유형을 추출해야합니다. 그렇지 않습니까? 나는 그것이 여기에 제안했던 것과 같은 것을하는 것이 훨씬 쉽다고 생각한다 : http://stackoverflow.com/questions/24326984/how-do-i-register-nsundomanager-in-swift/41619219#41619219 – MH175

+1

당신은 그렇게 할 수있다. 저는 여러분이 모든 단일 객체의 실행 취소 상태를 관리해야하는 상처를 겪고 있다고 생각합니다. 특히 객체 계층 구조에서 작업 할 때 특히 그렇습니다. 모든 속성에 대해 실행 취소 스택이 필요하다는 것을 명심하십시오. 게다가 모든 단일 ID 객체에서 undo()를 호출해야하므로이 경우에도 도움이되지 않습니다. 모델에 가능한 한 값 유형을 사용하는 것을 고려하십시오 - 값 유형은 예상대로 값을 캡처합니다. – MrMage