2012-04-15 5 views
0

я доступ к переданному уведомлению следующим образом:ИОС доступ потенциально неопределенный объект

[[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' 
} 

Некоторые из входящих note.object объектов имеют «колонтитул», а некоторые нет. Тем не менее, я не хочу переходить к проблеме создания класса, у которого есть только свойство, называемое footer, чтобы сделать эту работу. Я даже попробовал ((NSObject *)note.object).footer), который работает на некоторых языках, но, видимо, не obj-c. Что я могу сделать?

+0

Почему бы не пойти на неприятности? Классы ObjC довольно легкие по сравнению с большинством языков, и это позволит вам сравнить свойство нижнего колонтитула с nil. – CodaFi

ответ

2

Проверка isKindOfClass, безусловно, является более надежным вариантом. Однако, если у вас есть несколько несвязанных классов, которые возвращают требуемое свойство, существует другой способ: respondsToSelector. Просто спросите, есть ли у объекта метод footer, и вы можете спокойно его называть.

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

Это respondsToSelector метод является мощным и удобным в нужных местах, но не идут дикие с ним. Кроме того, он ничего не может рассказать о типе возвращаемого значения, поэтому вы можете получить footer того класса, которого вы ожидали.

Синтаксис для noteObject.footer и [noteObject footer] просты в обращении как эквивалентные. Однако, когда класс noteObject неизвестен, компилятор примет последнее, но не первое. Если noteObject имеет определенный класс, который обычно не отвечает на footer, он выдаст предупреждение, но все еще будет компилироваться и запускаться. В этих случаях ваша ответственность заключается в том, чтобы гарантировать, что метод действительно будет существовать, когда это необходимо, и, следовательно, вызов метода не будет аварийно завершен во время выполнения.

1

NSObject не имеет никакого имущества с именем footer, поэтому компилятор жалуется. Отбрасывание идентификатора обратно на NSObject не помогает. Если вы знаете, что объект всегда будет каким-то настраиваемым объектом, который вы создали, вы можете вернуться к нему, а затем вызвать нижний колонтитул, и компилятор не будет жаловаться. Лучше всего проверить тхо. Далее приведен пример (для примера, я назвал класс, который имеет footer свойство ViewWithFooter, поэтому переименовывать соответствующим образом):

- (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); 
} 

Если у вас есть куча несвязанных классов (то есть, не в той же иерархии классов) что все присутствуют в свойстве footer, вам лучше всего создать протокол с требуемым свойством footer и передать объект в протокол в приведенном выше примере кода и утверждать, что он отвечает на селектор -footer.

Вот пример с использованием протокола:

@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

для любопытства, есть ли способ обойти использование класса, используя что-то вроде '((id *) note.object) .footer' таким образом, что компилятор не будет сумасшедшим? – Jacksonkr

+0

Обход? Свойства требуют явного объявления. (также, чтобы быть педантичным, id уже является указателем). – CodaFi

+0

Вы можете использовать '[[note object] performSelector: @selector (footer)]'. Компилятор не будет жаловаться на это, но если 'footer' не реализован, вы получите обычный' EXC_BAD_ACCESS'. Если вы завершите вызов 'performSelector' в условии' responsesToSelector', вы будете закрыты. – mttrb

1

Если object прошло в уведомлении может быть один из нескольких классов, и вы не хотите, чтобы привести объект к определенному классу, вы можете использовать performSelector: для вызова footer метода объекта. Если вы завершите этот вызов respondsToSelector:, вы избежите исключения, если объект окажется не имеющим метод footer.

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

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

Использование performSelector остановит компилятор жалуется, что метод «„сноска“не найден на объект типа„ид“.»