ios访问可能未定义的对象

时间:2012-04-15 04:17:10

标签: ios cocoa-touch

我正在访问这样的已发送通知:

[[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。我该怎么办?

3 个答案:

答案 0 :(得分: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 :(得分:1)

NSObject没有任何名为footer的属性,这就是编译器抱怨的原因。将ID转换回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);
}

答案 2 :(得分:1)

如果通知中传递的object可能是众多类中的一个,并且您不想将对象强制转换为特定类,则可以使用performSelector:来调用{{1}对象上的方法。如果您使用footer打包此调用,则如果对象结果没有respondsToSelector:方法,则会避免异常。

footer

使用-(void)handleUnpresent:(NSNotification *)note; { if ([[note object] respondsToSelector:@selector(footer)]) { NSString *footer = [[note object] performSelector:@selector(footer)]; NSLog(@"%@", footer); } } 将阻止编译器抱怨在'id'类型的对象上找不到方法“'footer'。”