在未初始化的对象(空指针)上调用方法
Posted
技术标签:
【中文标题】在未初始化的对象(空指针)上调用方法【英文标题】:Calling a method on an uninitialized object (null pointer) 【发布时间】:2011-02-11 10:02:32 【问题描述】:-
如果您在一个对象(指针)上调用一个方法,该对象(指针)为 nil(可能是因为有人忘记初始化它),那么在 Objective-C 中的正常行为是什么?它不应该产生某种错误(分段错误,空指针异常......)吗?
如果这是正常行为,有没有办法改变这种行为(通过配置编译器),以便程序在运行时引发某种错误/异常?
为了更清楚我在说什么,这里有一个例子。
有这个课程:
@interface Person : NSObject
NSString *name;
@property (nonatomic, retain) NSString *name;
- (void)sayHi;
@end
使用此实现:
@implementation Person
@synthesize name;
- (void)dealloc
[name release];
[super dealloc];
- (void)sayHi
NSLog(@"Hello");
NSLog(@"My name is %@.", name);
@end
在程序的某个地方我这样做:
Person *person = nil;
//person = [[Person alloc] init]; // let's say I comment this line
person.name = @"Mike"; // shouldn't I get an error here?
[person sayHi]; // and here
[person release]; // and here
【问题讨论】:
【参考方案1】:发送到nil
对象的消息在Objective-C 中是完全可以接受的,它被视为无操作。无法将其标记为错误,因为它不是错误,实际上它可能是该语言的一个非常有用的特性。
来自docs:
向 nil 发送消息
在 Objective-C 中,发送一个 给 nil 的消息——它根本没有效果 在运行时。有几种模式 在 Cocoa 中利用这一点 事实。从 a 返回的值 发给 nil 的消息也可能有效:
如果方法返回一个对象,那么发送到
nil
的消息返回0
(nil
),例如:
Person *motherInLaw = [[aPerson spouse] mother];
如果
aPerson
的spouse
是nil
, 然后mother
被发送到nil
并且 方法返回nil
。如果方法返回任何指针类型,任何大小小于的整数标量 大于或等于
sizeof(void*)
,一个float
,一个double
,一个long double
, 或long long
,然后发送一条消息 到nil
返回0
。如果方法返回
struct
,如 Mac OS X ABI 所定义 要返回的函数调用指南 注册,然后将消息发送到nil
为每个字段返回0.0
数据结构。其他struct
数据类型不会被填充 零。如果方法返回的值不是上述值 类型消息的返回值 发送到 nil 是未定义的。
【讨论】:
而且我不知道有什么方法可以改变这种行为。它是使用 Objective-C/Cocoa 进行编程的基本部分。你会学会爱上它。【参考方案2】:来自Greg Parker的site:
如果运行 LLVM 编译器 3.0 (Xcode 4.2) 或更高版本
返回类型为 nil 的消息 |返回 高达 64 位的整数 | 0 浮点数高达 long double | 0.0 指针 |零 结构 | 0 任何_复杂类型 | 0, 0【讨论】:
【参考方案3】:您应该清楚的一点是,在 Objective-C 中,您不会调用对象的方法,而是向对象发送消息。运行时将找到该方法并调用它。
从 Objective-C 的第一个版本开始,给 nil 的消息一直是返回 nil 的安全无操作。有很多代码依赖于这种行为。
【讨论】:
【参考方案4】:什么也没发生。当您向 nil 发送消息时,这意味着没有接收者
然后消息飞走了。 objc_msgSend
方法来自 Runtime
库。使用Message dispatch
机制,这就是Objective-C
不同的原因,基于此原理有很多优点。它不会像Java
或Swift
那样抛出任何错误
【讨论】:
以上是关于在未初始化的对象(空指针)上调用方法的主要内容,如果未能解决你的问题,请参考以下文章
在 Activity 中调用 Fragment 方法会导致空指针异常