几乎所有面向对象的语言都会有ni这样的概念:不指向任何对象的指针。在Objective-C中,nil是值为0的指针。
多数面向对象的语言不允许向nil发送消息。所以在发送消息前,必须检查指针是否为nil,从而导致出现大量下面这类代码:
if(fido != nil){
[fido goGetTheNewspaper];
}
Objective-C则不同。在Objective-C中,可以向nil发送消息,什么事情也不会发生。
因此,下面这段代码是完全“合法”的:
Dog *fido = nil;
[fido goGetTheNewspaper];
重点1:如果程序向某个对象发送了消息,但却没有得到预期的结果,请检查消息接收方是否为nil。
重点2:向nil发送消息,得到的返回值没有意义。
当声明指向对象的指针时,通常都会明确地写出相应对象的类:
NSDate *expiration;
但是在编写程序时,很可能会碰到以下这种情况:声明指针时并不知道所指对象的准确类型。为此,可以使用id类型。id类型的含义是:可以指向任意类型Objective-C对象的指针。
id delegate;
注意:以上这则变量声明没有使用星号。id已经隐含了星号的作用。因为对象只能通过指针访问,所以人们常用指向对象的指针来称呼该对象,例如有的时候说“now是一个NSDate实例”。然而,一定要记住指针和它指向的对象是不同的。准确的说法应该是:“now是一个指针变量,它保存了NSDate实例在内存中的地址。”
栈是由有序的帧构成的,函数的帧在函数结束后会自动释放,而堆里的对象不会自动释放。
管理堆很重要,因为程序占用的堆大小是有限的。而每个对象被创建后都会占用一定的堆内存。
如果系统内存不足,MAC应用的运行效果就会变差,而IOS应用则会崩溃。因此,必须释放不需要的对象,将内存交还给系统,继续重新使用。
自动销毁不被引用的对象的机制称为ARC。ARC是自动引用计数(automatic reference counting)的简称。如果你还记得我们说过引用(reference)是指针的另一种叫法,那么理解ARC就比较容易了:每个对象都会对指向自己的指针进行计数。当引用数为0时,就会认为不需要该对象了,程序会自动销毁该对象。如果项目开启了ARC,编译器会自动给项目添加代码来计算每个对象的引用数。
只要有一个指针指向对象,这个对象就会继续存在。申请缓冲区,调用free()函数来销毁对象是清理得最干净的方法。使用ARC,只能通过增加或减少对对象的引用数来保留或者销毁对象。而只有当引用数为0时,它才会被销毁。
如果不再需要某个对象,则可以将指向它的指针设置为nil,或者销毁它的指针。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSDate *currentTime = [NSDate date];
NSLog(@"currentTime's value is %p",currentTime);
NSDate *startTime = currentTime;
sleep(2);
currentTime = [NSDate date];
NSLog(@"currentTime's value is now %p",currentTime);
NSLog(@"The address of the original object is %p",startTime);
//让currentTime变无效,从而销毁对象
currentTime = nil;
NSLog(@"currentTime's value is %p",currentTime);
}
return 0;
}
如果指针变量被销毁,则它指向的对象也会失去一个引用。当某个对象的实例变量指向其他对象的时候,事情会变得更加复杂。