2012-04-15 7 views
0

ich den Zugriff auf eine Benachrichtigung geschickt wie so:ios Zugriff potenziell Objekt undefined

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleUnpresent:) name:UNPRESENT_VIEW object:nil]; 

... 

-(void)handleUnpresent:(NSNotification *)note; 
{ 
    NSLog(@"%@", note.object.footer); 
    //property 'footer' not found on object of type 'id' 
} 

Einige der eingehenden note.object Objekte haben eine „Fußzeile“ und manche nicht. Ich möchte jedoch keine Schwierigkeiten machen, eine Klasse zu erstellen, die nur eine Eigenschaft mit dem Namen footer hat, nur um diese Arbeit zu erledigen. Ich habe sogar versucht ((NSObject *)note.object).footer), die in einigen Sprachen funktioniert, aber anscheinend nicht obj-c. Was kann ich tun?

+0

Warum nicht zu den Schwierigkeiten gehen? ObjC-Klassen sind im Vergleich zu den meisten Sprachen relativ leicht und ermöglichen es Ihnen, die Fußzeileneigenschaft mit Null zu vergleichen. – CodaFi

Antwort

2

Überprüfung der isKindOfClass ist sicherlich die robustere Option. Wenn Sie jedoch mehrere unabhängige Klassen haben, die die gewünschte Eigenschaft zurückgeben, gibt es einen anderen Weg: respondsToSelector. Fragen Sie einfach, ob das Objekt eine footer Methode hat, und Sie können es sicher anrufen.

-(void)handleUnpresent:(NSNotification *)note; 
{ 
    id noteObject = [note object]; 
    if ([note respondsToSelector:@selector(footer)]) 
    { 
     NSLog(@"Footer = %@", [noteObject footer]); 
    } 
} 

Die respondsToSelector Methode ist leistungsfähig und praktisch an den richtigen Stellen, aber gehen Sie nicht mit ihm wild. Außerdem kann es Ihnen nichts über den Rückgabetyp sagen, so dass die footer Sie nicht von der Klasse erhalten, die Sie erwartet haben.

Die Syntax für noteObject.footer und [noteObject footer] sind einfach als äquivalent zu behandeln. Wenn jedoch die Klasse noteObject unbekannt ist, akzeptiert der Compiler die letztere, aber nicht die erstere. Wenn noteObject über eine definierte Klasse verfügt, die normalerweise nicht auf footer reagiert, wird eine Warnung ausgegeben, aber trotzdem kompiliert und ausgeführt. In diesen Fällen liegt es in Ihrer Verantwortung sicherzustellen, dass die Methode tatsächlich bei Bedarf vorhanden ist und daher der Methodenaufruf zur Laufzeit nicht abstürzt.

1

NSObject hat keine Eigenschaft mit dem Namen footer, weshalb der Compiler beschweren wird. Eine ID zurück zu NSObject zu werfen hilft nicht. Wenn Sie wissen, dass das Objekt immer ein benutzerdefiniertes Objekt sein wird, das Sie erstellt haben, können Sie es zurückwerfen und dann die Fußzeile aufrufen, und der Compiler wird sich nicht beschweren. Es ist am besten, tho tatsächlich zu überprüfen. Siehe das Beispiel unten (für das Beispiel nannte ich die Klasse, die die footer Eigenschaft hat ViewWithFooter, so umbenennen angemessen):

- (void)handleUnpresent:(NSNotification*)note 
{ 
    ViewWithFooter view = (ViewWithFooter*)[note object]; 
    NSParameterAssert([view isKindOfClass:[ViewWithFooter class]]); 
    UIView* footer = [view footer]; 
    // Do something with the footer... 
    NSLog(@"Footer: %@", footer); 
} 

Wenn Sie eine Reihe von nicht verwandten Klassen haben (dh nicht in der gleichen Klassenhierarchie) dass alle eine footer Eigenschaft darstellen, würden Sie am besten bedient werden, indem Sie ein Protokoll mit der erforderlichen footer -Eigenschaft erstellen und das Objekt auf das Protokoll im obigen Codebeispiel umwandeln und bestätigen, dass es auf den Selektor antwortet.

Hier ist ein Beispiel unter Verwendung des Protokolls:

@protocol ViewWithFooter <NSObject> 

- (UIView*)footer; // this could also be a readonly property, or whatever 

@end 

- (void)handleUnpresent:(NSNotification*)note 
{ 
    id<ViewWithFooter> view = (id<ViewWithFooter>)[note object]; 
    NSParameterAssert([view respondsToSelector:@selector(footer)]); 
    UIView* footer = [view footer]; 
    // Do something with the footer... 
    NSLog(@"Footer: %@", footer); 
} 
+0

aus Neugier, gibt es eine Möglichkeit, eine Klasse zu umgehen, indem Sie etwas wie '((id *) note.object) .footer' in einer Weise, dass der Compiler wird nicht böse sein? – Jacksonkr

+0

Bypass? Eigenschaften erfordern eine explizite Deklaration. (Um pedantisch zu sein, ist id bereits ein Zeiger). – CodaFi

+0

Sie könnten '[[note object] performSelector: @selector (Fußzeile)]' verwenden. Der Compiler wird sich darüber nicht beschweren, aber wenn 'footer' nicht implementiert ist, erhalten Sie die übliche' EXC_BAD_ACCESS'. Wenn Sie den Aufruf von 'performSelector' in eine' responseToSelector'-Bedingung umbrechen, werden Sie abgedeckt. – mttrb

1

Wenn die object in der Anmeldung bestand aus einer Anzahl von Klassen sein kann und Sie nicht wollen, um das Objekt zu einer bestimmten Klasse werfen Sie performSelector: rufen die footer Methode für das Objekt verwenden können. Wenn Sie diesen Aufruf mit einem respondsToSelector: umbrechen, vermeiden Sie eine Ausnahme, wenn das Objekt keine footer-Methode aufweist.

-(void)handleUnpresent:(NSNotification *)note; 
{ 
    if ([[note object] respondsToSelector:@selector(footer)]) { 
     NSString *footer = [[note object] performSelector:@selector(footer)]; 

     NSLog(@"%@", footer); 
    } 
} 

performSelector verwendet, wird der Compiler aufhören, zu jammern, dass die Methode „‚Fußzeile‘nicht auf Objekt vom Typ‚id‘gefunden.“

Verwandte Themen