2013-02-13 10 views
7

Eine Idee, was sind die besten Praktiken für die Archivierung eines NSViewController in einem Fenster für resume (Benutzeroberfläche Erhaltung) Zwecke? Ich habe versucht, es in den encodeRestorableStateWithCoder: Methoden des Fenstercontrollers zu archivieren, nur um herauszufinden, dass der Ansichtsteuerpult nicht entpackt wird, wenn restoreStateWithCoder: aufgerufen wird.Encoding NSViewController für Lions Benutzeroberfläche Wiederaufnahme-Funktion

// 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; 
    } 
} 

Beachten Sie, dass diese Ansicht-Controller andere Ansicht-Controller enthält, die ihre eigenen Subviews schafft und damit eine gewisse Scoping im NSCoder Instanz müssen - einfach die mitgelieferten coder nach unten Objekt übergeben werden Namenskonflikte im Archiv verursachen.

Vielen Dank im Voraus!

+0

Es könnte sein, verwenden Sie sichere Codierung, haben Sie versucht '-decodeObjectOfClass: forKey:' stattdessen? – Pol

Antwort

5

Staatsrestaurierungsarbeiten kostenlos auf NSView aber auf NSViewController sogar ignoriert, obwohl es die Methoden als Unterklasse von NSResponder implementiert. Ich vermute, das liegt daran, dass das Fenster nichts über NSViewControllers weiß, die einige der enthaltenen Ansichten besitzen könnten.

Auf OS X Yosemite soll es funktionieren, seit NSWindow hat jetzt echte Unterstützung für NSViewControllers, aber es ist nicht in meinen Testfällen. Ich denke, das liegt daran, dass man die NSViewControllers mit den neuen APIs "verketten" muss, um sie hinzuzufügen/zu entfernen, anstatt sie auf der Seite zu erstellen und ihre Ansichten direkt in das Fenster einzufügen. Letzteres ist tatsächlich erforderlich, wenn Sie Ihre App trotzdem auf Yosemite-Systemen ausführen lassen möchten.

Hier ist, wie es immer funktioniert: Proxy einfach die Wiederherstellung APIs Anrufe zwischen NSView und NSViewController.

Subclass NSView wie folgt aus:

@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 

Und NSViewController wie folgt aus:

@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 

Jetzt können Sie -invalidateRestorableState aus der NSViewController Unterklasse und Cocoa nennen, zu sprechen eine NSView es denkt, rufen automatisch -encodeRestorableStateWithCoder: und -restoreStateWithCoder: auf Ihrer NSViewController Unterklasse nach Bedarf.

+0

Hallo, das ist ein netter Trick :) Ich versuche, die Wiederherstellung auch auf einer Mac-App zu implementieren, und ich bekomme die Wiederherstellungsaufrufe nicht einmal für die NSView-Unterklassen. Irgendeine Idee was das sein könnte? Ich habe dafür einen neuen Thread erstellt: http://stackoverflow.com/q/42010026/3251155 –

0

Ich habe nicht mit wiederherstellbaren Zustand vieler (Jonathon Mah hat es für DL3) messed aber wenn ich dies tat, ich würde versuchen, diese beiden Methoden zu löschen und + restorableStateKeyPaths zu implementieren, zB:

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

Und seht nur, ob die Maschinerie alles für mich erledigt hat.

+ (NSArray *)restorableStateKeyPaths; 

Gibt einen Satz von Schlüsselpfade repräsentieren Pfade von Eigenschaften, die persistent sein sollte. Die Frameworks beobachten diese Schlüsselpfade über KVO und behalten ihre Werte automatisch als Teil des persistenten Status bei und stellen sie beim Relaunch wieder her. Die Werte der Schlüsselpfade sollten die Schlüsselarchivierung implementieren. Die Basisimplementierung gibt ein leeres Array zurück.

+0

Dies würde funktionieren, wenn 'contentViewController' dieselbe Klasse (also denselben Satz wiederherstellbarer Eigenschaften) für den Fenstercontroller hat. Leider ist der View-Controller unter einer guten Anzahl von Klassen austauschbar. Denken Sie an die offizielle Twitter-App mit austauschbaren Ansichten, je nachdem, was Sie in der linken "Tab" -Leiste ausgewählt haben. Entsprechend sind die View-Controller auch entsprechend der von ihnen gesteuerten Top-Level-Ansichten austauschbar. – adib