2013-02-13 1 views
7

resume (사용자 인터페이스 보존)을 위해 창안에 NSViewController을 보관하는 것이 가장 좋은 방법은 무엇입니까? 나는 창 컨트롤러의 encodeRestorableStateWithCoder: 메서드에서만 보관을 시도하여 restoreStateWithCoder:이 호출 될 때보기 컨트롤러가 아카이브되지 않는다는 것을 알아 냈습니다. 단순히 아카이브에서 이름 충돌의 원인이됩니다 제공된 coder 객체 아래를 통과 -이 뷰 컨트롤러가 NSCoder 인스턴스의 일부 범위 지정이 필요합니다, 따라서 자신의 파단을 관리하고, 다른 뷰 컨트롤러를 포함Lion의 사용자 인터페이스 재개 기능을위한 NSViewController 인코딩

// NSWindowController subclass 

-(void)encodeRestorableStateWithCoder:(NSCoder *)coder 
{ 
    [super encodeRestorableStateWithCoder:coder]; 
    NSViewController* contentViewController = self.contentViewController; 
    if (contentViewController) { 
     [coder encodeObject:contentViewController forKey:BSContentViewControllerResumeKey]; 
    } 
} 

-(void)restoreStateWithCoder:(NSCoder *)coder 
{ 
    [super restoreStateWithCoder:coder]; 
    NSViewController* contentViewController = [coder decodeObjectForKey:BSContentViewControllerResumeKey]; 
    if (contentViewController) { 
     // somehow this never get executed since contentViewController always comes out nil 
     self.contentViewController = contentViewController; 
    } 
} 

참고.

미리 감사드립니다.

+0

보안 코딩을 사용 중일 수 있습니다. 대신'-decodeObjectOfClass : forKey :'를 시도 했습니까? – Pol

답변

5

주 복원 NSView에 무료로 작동하지만 그것은 NSResponder의 서브 클래스로 메소드를 구현하더라도 NSViewController 무시됩니다. 창에 포함 된 뷰의 일부를 소유 할 수있는 NSViewController에 대해 알지 못하기 때문입니다.

OS X에서 요세미티는 현재 NSWindow이 (가) NSViewControllers에 대한 실질적인 지원을하고 있기 때문에 작동하지만, 테스트 케이스에서는 그렇지 않습니다. 그것은 새로운 API를 사용하여 NSViewControllers를 "체인화"하여 추가/삭제할 필요가 있고 사이드에 직접 생성하고 뷰를 윈도우에 직접 추가해야하기 때문입니다. 어쨌든 사전 요세미티 시스템에서 앱을 실행하려면 후자가 실제로 필요합니다.

항상 작동하게하는 방법은 다음과 같습니다. 복원 API 호출을 NSViewNSViewController 사이에서 프록시 처리하면됩니다. 이 같은

서브 클래스 NSView이 같은

@interface GIView : NSView 
@property(nonatomic, weak) GIViewController* viewController; // Avoid retain-loops! 
@end 

@implementation GIView 

- (void)setViewController:(GIViewController*)viewController { 
    _viewController = viewController; 
} 

- (void)encodeRestorableStateWithCoder:(NSCoder*)coder { 
    [super encodeRestorableStateWithCoder:coder]; 

    [_viewController encodeRestorableStateWithCoder:coder]; 
} 

- (void)restoreStateWithCoder:(NSCoder*)coder { 
    [super restoreStateWithCoder:coder]; 

    [_viewController restoreStateWithCoder:coder]; 
} 

@end 

그리고 NSViewController :

@interface GIViewController : NSViewController 
@end 

@implementation GIViewController 

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { 
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { 
    self.view.viewController = self; // This loads the view immediately as a side-effect 
    } 
    return self; 
} 

- (void)dealloc { 
    self.view.viewController = nil; // In case someone is still retaining the view 
} 

- (void)invalidateRestorableState { 
    [self.view invalidateRestorableState]; 
} 

@end 

지금 당신이이 NSView 이야기의 생각은 NSViewController 서브 클래스와 코코아에서 -invalidateRestorableState를 호출 할 수 있습니다 자동으로 호출 필요에 따라 NSViewController 하위 클래스의 -encodeRestorableStateWithCoder:-restoreStateWithCoder:

+0

안녕하세요, 이것은 멋진 트릭입니다. 저는 Mac 응용 프로그램에서도 복원을 구현하려고하는데 NSView 하위 클래스에 대해서도 복원 호출을받지 못합니다. 그게 뭔데? 나는 그것을 위해 새로운 스레드를 만들었습니다 : http://stackoverflow.com/q/42010026/3251155 –

0

나는 많은 복원 가능한 상태로 엉망이되지 않은 (조나단 맣은 DL3을 위해 그것을했다)하지만 난이 일을한다면 나는 그 두 가지 방법을 삭제하려고 + restorableStateKeyPaths, 예를 구현하는 것 :

+ (NSArray *)restorableStateKeyPaths; 
{ 
    return @[@“contentViewController.firstInterestingStateProperty”, @“contentViewController.secondInterestingStateProperty”]; 
} 

을 그리고 기계가 나를 위해 모든 것을 다 처리하는지 확인하십시오.

+ (NSArray *)restorableStateKeyPaths; 

는 가 지속되어야한다 속성의 경로를 나타내는 주요 경로의 세트를 돌려줍니다. 프레임 워크는 KVO를 통해 이러한 주요 경로를 관찰하고 영구적 인 상태의 일부로 해당 값을 자동으로 유지하고 다시 시작할 때이를 복원합니다. 키 경로 의 값은 키 저장을 구현해야합니다. 기본 구현은 빈 배열을 반환합니다.

+0

'contentViewController'가 윈도우 콘트롤러와 같은 클래스 (따라서 동일한 복원 가능 속성 세트) 인 경우에 효과적입니다. 불행히도 뷰 컨트롤러는 많은 수의 클래스 사이에서 스왑 가능합니다. 왼쪽의 "탭"바에서 선택한 내용에 따라 교체 가능한보기가있는 공식 Twitter 앱을 생각해보십시오. 마찬가지로 뷰 컨트롤러는 자신이 제어하는 ​​최상위 뷰에 따라 스왑 가능합니다. – adib

관련 문제