2016-09-18 8 views
4

Xcode 7/Swift 2.2 Mac OS X 프로젝트를 Xcode 8/Swift 3으로 마이그레이션 할 때 뷰 컨트롤러 클래스에서 undoManager를 사용하여 문제가 발생했습니다. MyViewController - 실행 취소 기능이 있습니다.Swift 3에서 NSUndoManager 및 .prepare (withInvocationTarget :) 사용

엑스 코드 7/스위프트 2.2, 이는 잘 작동 :

if let target = undoManager?.prepare(withInvocationTarget: self) as? MyViewController { 
    target.undo(data, moreData: moreData) 
    undoManager?. setActionName("Change Data") 
} 
:

undoManager?.prepareWithInvocationTarget(self).undo(data, moreData: moreData) 
undoManager?.setActionName("Change Data) 

엑스 코드 8/스위프트 3 https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html

에서 권장되는 패턴을 이용하여이 변경되어야

그러나 MyViewController 다운 캐스트는 항상 실패하고 실행 취소 작업은 등록되지 않습니다.

여기에 명백한 내용이 없거나 버그입니까?

답변

7

prepareWithInvocationTarget(_:) (또는 Swift 3에서 prepare(withInvocationTarget:))은 숨겨진 프록시 객체를 만듭니다.이 객체를 사용하면 Swift 3 런타임이 제대로 작동하지 않을 수 있습니다.

(당신은 버그 및 버그 리포트를 보내 줄 것을 요청할 수있다.)

목적을 달성하기 위해, 당신은 registerUndo(withTarget:handler:)을 사용할 수 없습니다?

undoManager?.registerUndo(withTarget: self) {targetSelf in 
    targetSelf.undo(data, moreData: moreData) 
} 
+0

감사합니다. 나는 그걸 가지고 놀았습니다. 불행히도 OS10.10과 호환되지는 않지만 계속 진행할 수있는 시간입니다. – jbaraga

+1

OS 10.10의 해결책 :'registerUndo (with : Target : selector : object :)'를 사용하십시오. 단일 값을 저장하는 데는 아무런 문제가 없습니다. 여러 값을 저장하기 위해 사전에 압축하여 "object"매개 변수로 사용합니다. 실행 취소 작업의 경우 사전에서 압축을 풉니 다. – jbaraga

+0

@jbaraga, 신고 해 주셔서 감사합니다. 그런데 왜 다른 답변으로 게시하지 않습니까? 10.10에서 작업해야하는 개발자에게는 도움이 될 수 있습니다. – OOPer

1

OS 10.10과 역 호환성을위한 솔루션은 registerUndo(with Target: selector: object:)입니다. 단일 값을 저장하는 데는 아무런 문제가 없습니다. 여러 값을 저장하기 위해 사전에 압축하여 "object"매개 변수로 사용합니다. 실행 취소 작업의 경우 사전에서 압축을 풀고 해당 값으로 OS10.11 + 실행 취소 메소드를 호출합니다.

+0

감사합니다. "다중 값"사례 코드를 포함하면 더 많은 사람들이 귀하의 대답을 쉽게 찾을 수 있습니다. 그것에 시간을 할애 해보십시오. – OOPer

2

저도 같은 문제를 했어 나는 아이폰 OS 8과 맥 OS 10.10 지원을 떨어 뜨리거나 스위프트 2.3로 돌아갈 준비가되지 않았습니다. registerUndo(withTarget:handler) 구문은 비록 좋은, 그래서 나는 기본적으로 그냥 내 자신의 버전 압연 :

/// An extension to undo manager that adds closure based 
/// handling to OS versions where it is not available. 
extension UndoManager 
{ 
    /// Registers an undo operation using a closure. Behaves in the same wasy as 
    /// `registerUndo(withTarget:handler)` but it compatible with older OS versions. 
    func compatibleRegisterUndo<TargetType : AnyObject>(withTarget target: TargetType, handler: @escaping (TargetType) ->()) 
    { 
     if #available(iOS 9.0, macOS 10.11, *) 
     { 
      self.registerUndo(withTarget: target, handler: handler) 
     } 
     else 
     { 
      let operation = BlockOperation { 
       handler(target) 
      } 
      self.registerUndo(withTarget: self, selector: #selector(UndoManager.performUndo(operation:)), object: operation) 
     } 
    } 

    /// Performs an undo operation after it has been registered 
    /// by `compatibleRegisterUndo`. Should not be called directly. 
    func performUndo(operation: Operation) 
    { 
     operation.start() 
    } 
} 

잘하면 다른 너무 사람에게 도움을.