1、一、Objective-C 的内存回收机制在 Objective-C 中采用的是引用计数的内存回收方式。凡是继承 NSObject 的类生成的对象,当对象的计数为 0,会对对象执行 dealloc 并回收。二、alloc, retain, release1、alloc:用来分配内存,在利用 alloc 生成分配了一个对象内存后,该对象的引用计数是 1。如:ClassA *obj = ClassA alloc init; /retainCount 为 12、release:用来将对象的引用计数减一, 当我们不在需要这个对象调用 obj 的 release方法使引用计数变为 0, http:/ o
2、bj 的 dealloc 方法会被自动调用。接上例:obj release; /retainCount 减一变为 0,obj 的 dealloc 会被调用3、 retain:用来将对象的引用计数加一。如:ClassA *obj = ClassA alloc init; /retainCount 为 1obj retain; /retainCount 为 2/do somethingobj release; /retainCount 为 1obj release; /retainCount 为 0,调用 dealloc 对象释放在这个环节上容易出的错误:ClassA *obj1 = ClassA
3、 alloc init; /ClassA 里面有个 名为 hello 的 functionClassA *obj2 = obj1;/do something with obj1 and obj2obj1 hello;obj1 release; /对象已经释放掉了obj2 hello; /崩溃,obj2 已经是野指针了obj2 release;三、autorelease, NSAutoreleasePool 和工厂方法1 、 NSAutoreleasePool:在开发的过程中会出现内存申请者经常会出现内存申请者和内存使用者之间的交互问题,比如,一个函数内部申请了内存,做了一些操作,然后返回这块内
4、存。这个时候调用者要负责对这块内存执行清理工作,在调用栈很深的情况下,很容易产生内存泄露。而且这种内存解决方案破坏了内存由谁生成由谁释放的原则。为了解决这个问题,产生了 NSAutoreleasePool。使用方法如下:NSAutoreleasePool * pool = NSAutoreleasePool alloc init; /创建一个 release poolClassA *obj = ClassA alloc init autorelease; /创建一个对象并将它加入 release poolobj retainCount; /retainCount 为 1/do somethin
5、gpool release; /在 release pool 被释放的时候将 obj 的引用计数自动减一,这时/obj 的 releaseCount 变为了 0,obj 被释放对象在被 autorelease 时他的引用计数并没有立即减少,而是在 release pool 被释放的时候引用计数才减一的。在对象被2、工厂方法:在 UIKit 提供的类中经常会看到 static 方法创建出的对象,如:NSNumber *numObj = NSNumber numberWithInt: 1;从设计模式的角度上讲这个 static 方法创建了,一个对象,这中利用公共方法创建对象的模式叫做工厂方法。在
6、Objective-C 中的程序设计中有个规则,就是这种工厂方法返回的对象都是不需要调用者 release 的,http:/ 因为虽然他们现在的引用计数为 1,但是他会自动释放。(因为他们在返回对象的时候都对其调用了 autorelease)3、深入讲解 NSAutoreleasePoolNSAutoreleasePool 是苹果公司实现的类,我们无法知道他是怎么实现的,但是可以确定的是,在对象调用 autorelease 的时候,距离对象最近的 NSAutoreleasePool 将记录该对象,并在 autorelease pool 释放时将对象的计数减一。NSAutoreleasePool
7、 *pool1 = NSAutoreleasePool alloc init; /创建第一个 release poolClassA *obj1 = ClassA alloc init autorelease; /生成一个对象,调用 autorelease,对象/被加载到 pool1 里,obj1的引用计数为 1obj1 retain; /obj1 引用计数加 1,变为 2NSAutoreleasePool *pool2 = NSAutoreleasePool alloc init; /创建第二个 release poolClassA *obj2 = ClassA alloc init auto
8、release; /生成另一个,调用 autorelease,对象/被加载到 pool2 里,obj2的引用计数为 1obj1 autorelease; /obj1 调用 autorelease,被加载到 pool2 里,引用计数为 2pool2 release; /释放 pool2,obj1 的引用计数减1,变为 1/obj2 的引用计数减 1,变为 0,obj2 对象释放poo1 release; /释放 pool1,obj1 的引用计数减 1,变为 0,obj1 对象释放NSAutoreleasePool 是需要在 release 自身的时候对挂在它上面的对象(调用过 autorelea
9、se 的对象)进行引用计数减一的,但是,我们能看见的显式创建的 NSAutoreleasePool 只在 main 函数中有创建,难道程序在运行过程中调用 autorelease 的对象必须在程序退出时释放么?绝对不可能,如果是在 main 函数结束时释放,在程序运行中必然造成内存使用量一直上升。 实际上,在主线程运行中,系统会自动创建一个 NSAutoreleasePool 并在一次绘图完成以后释放这个 pool。(忘记看了那份文档说的了,自己实验的结果是如此,等我找到了文档再分享给大家)四、声明一个 property,利用 assign, retain 或者 copy利用 property
10、 可以快速创建一个属性利用 property 创建一个属性之后,根据设置(assign, retain 或者 copy)系统生成的 Setter 和 Getter 是不同的。(以 NSString 为例)在调用 self.name 进行赋值时会调用 setter(setName:)在进行取值时会调用 getter(getName)公用部分:/.h 文件property (nonatomic, XXXX) NSString *name;/.m 文件synthesize name = _name;1. 如果 XXXX 是 assign,系统会自动生成 setter 和 getter 如下:sett
11、er:- (void) setName: (NSString *) newName _name = newName;getter:- (NSString *) getName return _name;2. 如果 XXXX 是 retain,系统会自动生成 setter 和 getter 如下:setter:- (void)setName: (NSString *)newName if (_name = newName) return;_name release; /旧的对象引用计数减一_name = newName retain; /将新的对象引用计数加一getter:- (NSString
12、 *) getName return _name;3.如果 XXXX 是 copy,系统会自动生成 setter 和 getter 如下:setter:- (void)setName: (NSString *)newName if (_name = newName) return;_name release; /旧的对象引用计数减一_name = newName copy; /将新的对象引用计数加一,getter:- (NSString *) getName return _name;_name 是一个属性,如果对其直接做赋值操作,是不会对对象的引用计数产生影响的,因此尽量不要直接对其进行赋值
13、操作,可以避免很多错误。如果是用 retain 和 copy 声明的属性,有一些场景需要直接对_name 执行释放(如需要立即释放内存的 dealloc,关掉网络请求等),这时要直接调用_name release将内存释放,并且将_name 变量设置为 nil。if (_name != nil) _name release, _name = nil;/或者self.name = nil;/错误的方式if(_name != nil) _name release; / _name 引用计数为 0, _name 所指被释放self.name = nil; /这里肯定崩溃, 因为在前面,_name 已经被 release 了。/但由于 _name 没有赋值为 nil,变成了野指针。/前面说过, self.name 执行的 setter 会先将/旧的 _name 执行 release,这时造成崩溃。上面这个错误是典型的由于野指针引起的崩溃,请大家务必注意。五、其他注意事项1. 自己创建了 thread 后,第一件事就是创建 NSAutoreleasePool。(来自苹果线程安全手册)2. NSArray,NSDictionary,NSSet 等容器类会自动将引用添加到其中的对象引用计数加一,当移除对象或者释放容器对象自身的时候引用计数减一。