Learn Objective‐C
id类型已经被预定义为指针类型
访问器
-----------------------------------------------------------------------------------------------------------------------------------
在Objective‐C中,所有的实例变量默认都是私有的,所以,在大多数情况下,你应 该使用访问器来获取或设置这些变量的值。
在Objective-C中,大多数情况你不用在获取器(getter)前面添加一个”get”前缀
编译器会默认一个方法的返回值是一个id类型的对象,所有的输入参数也默认是id 类型。
释放一个对象的引用实际上有两种方法:release 和 autorelease。标准的 release会立刻释放对象的引用。autorelease会等一会儿才释放,但是引用实际上 会一直存在,直到当前方法结束(除非你添加自定义的代码来明确的改变它)。
在设置器里面使用autorelease方法会更加安全一些,因为要改变的变量的新旧两 个值可能指向的是同一个对象。而你可能不希望立刻释放实际上你要保留的对象。
创建对象
-----------------------------------------------------------------------------------------------------------------------------------
NSString* myString = [[NSString alloc] init];
这是一个嵌套的方法调用。第一个是NSString类本身的alloc方法调用。这是一 个相对低层的调用,它的作用是分配内存及实例化一个对象。
第二个是调用新创建对象的init方法。init方法通常做对象的初始化设置工作, 比如创建实例变量。作为一个类的使用者,你无法知道这些方法的实现细节。
在某些情况下,你可以使用init方法的另外一种版本,这些版本带有输入参数: NSNumber* value = [[NSNumber alloc] initWithFloat:1.0];
Init
-----------------------------------------------------------------------------------------------------------------------------------
我们可以创建一个init方法用来给我们的实例变量设置初始化值: - (id) init {
}
if ( self = [super init] ) {
[self setCaption:@"Default Caption"]; [self setPhotographer:@"Default Photographer"];
} return self;
这段代码是完全不需要加以说明的,尽管第二行看上去有点不常见。它是一个单个 的等号(=),作用是将[super init]的结果赋值给self。这实际上是要求父类做(父类的)初始化操作。if语句的作用是在尝试设置(本对 象的)缺省值之前验证父类是否初始化成功。
Dealloc
-----------------------------------------------------------------------------------------------------------------------------------
dealloc方法在一个对象从内存中删除时被调用。通常在这个方法里面释放所有对象 里的实例变量。
‐ (void) dealloc {
[caption release]; [photographer release]; [super dealloc];
}
在前两行,我们直接调用了实例变量的release方法。在这里,我们不需要使用 autorelease,因为标准的release更快一些。
最后一行非常重要,我们发送了一个[super dealloc]消息,要求父类做清理工作。如 果我们不做的话,该对象就不会被从内存中删除,这就造成了内存泄露。
当启用垃圾回收机制时,对象的dealloc方法不会被调用。此时,你可以实现一个 finalize方法来代替它。
内存管理
-----------------------------------------------------------------------------------------------------------------------------------
在实际应用中,通常只有两个原因我们才会创建一个对象: 1.作为一个实例变量保留。 2.在函数内部作为临时变量使用。 大多数情况下,一个实例变量的设置器(setter)会自动释放(autorelease)
原来引用的对象,同时保留(retain)新的。你只需要保证在dealloc函数中释放 (release)了它就行了。
那么,我们实际要做的工作就只有管理函数内部的本地引用了。在这里只有一条规 则:如果过你通过alloc或者copy创建了一个对象,在函数结尾的地方给它发送一个release或者autorelease消息就行了。如果你是通过其它方式创建的对象,就什么 也别做。
注意,不论你是不是把本地引用当成实例变量一样赋值,管理它们都是完全相同的。 你不必考虑设置器(setter)是如何实现的。
如果你理解了这些,你就理解了关于Objective-C内存管理中90%你需要知道的内 容。
日志记录
-----------------------------------------------------------------------------------------------------------------------------------
NSLog函数调用该对象的 description方法,并且将这个方法返回的NSString打印到控制台。你可以在你的 类中重写这个方法以返回你自定义的字符串。
属性(Properties)
-----------------------------------------------------------------------------------------------------------------------------------
只有当访问器不存在的时候,@synthesize才会自动生成访问器,所以,即使是使 用@synthesize声明了一个属性,你仍然可以实现自定义的getter和setter。编译 器只会自动生成你没有自定义的方法。
在Nil上调用方法
-----------------------------------------------------------------------------------------------------------------------------------
在Objective-C中,nil对象的作用等同于很多其他语言的NULL指针。不同的地 方在于,在nil上调用方法不会导致程序崩溃或抛出异常。
这种技术被用在很多地方,但是对于我们来讲,最主要的就是我们不用在调用一个 对象的方法之前检查该对象是否为空。如果你调用了一个nil对象的方法并且该方法有 返回值的话,你会得到一个nil返回值。
我们也可以用它来稍微改进一下我们的dealloc方法: - (void) dealloc {
self.caption = nil; self.photographer = nil; [super dealloc];
}
可以这样做是因为当我们将nil赋值给一个实例变量,设置器(setter)会释放旧对 象并且保留(retain)nil对象。这种做法对于dealloc来说更好一些,因为这样做 避免了让变量指向一个随机的数据,而这个数据又恰好是另外一个对象。
注意,我们在这里使用了self.<var>语法,这表示我们使用的是setter,它会进 行内存管理。如果我们仅仅是直接设置值,像下面这样,那就会产生内存泄露:
// incorrect. causes a memory leak. // use self.caption to go through setter caption = nil;
类目(Category)
-----------------------------------------------------------------------------------------------------------------------------------
与子类不同,你不能通过类目来添加实例变量。但是你能通过类目重写(override) 类中已经存在的方法,当然,重写的时候要特别小心。
记住,当你通过类目更改一个类的时候,这个更改会影响你这个应用程序中所有这 个类的实例。