2013-02-13 7 views
7

Qualsiasi idea di quali sono le migliori pratiche per l'archiviazione di un NSViewController all'interno di una finestra per resume scopi (conservazione interfaccia utente)? Ho provato l'archiviazione nel encodeRestorableStateWithCoder: metodi del controller finestra solo per scoprire che il controller della vista non ottiene non archiviata quando restoreStateWithCoder: si chiama.Codifica NSViewController per l'interfaccia utente funzione di ripristino del Leone

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

Si noti che questo controller di vista contiene altri controller di vista che gestisce i propri subviews, e quindi avrà bisogno di un po 'di scoping nell'istanza NSCoder - semplicemente passando le previste coder verso il basso oggetto causerà nome scontri in archivio.

Grazie in anticipo!

+0

Potrebbe essere utilizzando utilizzando la codifica sicuro, hai provato '-decodeObjectOfClass: Forkey:' invece? – Pol

risposta

5

restauro Stato lavora gratis su NSView ma viene ignorato il NSViewController anche se implementa i metodi come una sottoclasse di NSResponder. Suppongo che sia perché la finestra non sa di NSViewControllers che potrebbero possedere alcune delle viste che contiene.

Su OS X Yosemite dovrebbe funzionare dal NSWindow ora ha un supporto reale per NSViewControllers, ma non nei miei casi di test. Credo che sia perché si ha la necessità di "catena" i NSViewControllers utilizzando le nuove API per aggiungere/rimuovere le vs crearli sul lato e semplicemente aggiungendo le proprie opinioni direttamente alla finestra. Quest'ultimo è effettivamente necessario se si desidera che l'app venga eseguita su sistemi pre-Yosemite.

Ecco come farlo funzionare sempre: semplicemente proxy le chiamate API di ripristino tra NSView e NSViewController.

sottoclasse NSView come questo:

@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 

E NSViewController come questo:

@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 

Ora è possibile chiamare -invalidateRestorableState dal NSViewController sottoclasse e Cocoa, pensando che sta parlando a un NSView, chiamerà automaticamente -encodeRestorableStateWithCoder: e -restoreStateWithCoder: sulle tue NSViewController sottoclasse, se necessario.

+0

Ciao, questo è un bel trucco :) Sto cercando di implementare il ripristino anche su un'app mac e non ricevo le chiamate di ripristino anche per le sottoclassi NSView. Qualche idea di cosa potrebbe essere? Ho creato un nuovo thread per questo: http://stackoverflow.com/q/42010026/3251155 –

0

non ho pasticciato con stato ripristinabile molto (Jonathon Mah ha fatto per DL3), ma se fossi facendo questo mi piacerebbe provare l'eliminazione di questi due metodi e implementare + restorableStateKeyPaths, ad esempio:

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

E solo vedere se il macchinario ha gestito tutto per me.

+ (NSArray *)restorableStateKeyPaths; 

restituisce un insieme di percorsi principali, che rappresentano percorsi di proprietà che dovrebbe essere persistenti. I quadri osserveranno questi percorsi principali tramite KVO ed automaticamente persistono loro valori nell'ambito del persistente stato, e ripristinarli sul rilancio. I valori dei percorsi chiave devono implementare l'archiviazione con chiave. L'implementazione di base restituisce un array vuoto .

+0

Funzionerebbe se 'contentViewController' è la stessa classe (quindi lo stesso set di proprietà ripristinabili) per il controller della finestra. Sfortunatamente il controller della vista è scambiabile tra un buon numero di classi. Pensa all'app Twitter ufficiale, con le visualizzazioni scambiabili a seconda di ciò che hai selezionato nella barra "tab" a sinistra. Allo stesso modo i controller di visualizzazione sono anche scambiabili in base alle visualizzazioni di livello superiore che controllano. – adib

Problemi correlati