一、关于Alloc Retain Release 等
Aciton for Object-C Object |
Objective-C Method |
Create and have ownership of it | alloc/new/copy/mutableCopy group |
Take ownership of it | retain |
Relinquish it | release |
Dispose of it | dealloc |
alloc:创建一个对象,并拥有这个对象的使用权利。The implementation of alloc in NSObject:
关于NSZone: 是苹果对内存分配和释放的优化方式。NSZone不是一个对象;它是一个难懂的C结构,它被用于纪录关于内存处理(管理)一系列对象的信息。 你几乎不需要担忧你自己的应用(applications)是怎样管理你自己的空间(zones)的 ;Cocoa透明地管理它。默认的NSZone在程序启动和所有对象被分配时创建。 如果你大量分配数百个小对象,事实上你会发现你花费精力来为他们分配内存是有意义的。因为这种标准的(默认的)空间会被一直使用,它会变得斑驳起来;释放对象的过程会给整个内存留下令人尴尬的空隙。标准空间的分配器(allocator)也知道知道这一点,所以它尝试着优先去使用被用户释放的内存,去填补这些空隙,但是这种方式只有在空间(zone) 变得很大时才有明显效果。
使用NSZone + (id) alloc {return [self allocWithZone: NSDefaultMallocZone()]; } + (id) allocWithZone: (NSZone*)z {return NSAllocateObject (self, 0, z); } struct obj_layout { NSUInteger retained; }; inline id NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone *zone) { int size = /* needed size to store the object */ id new = NSZoneMalloc(zone, size); // 调用NSZoneMalloc 开辟一块内存空间,返回内存地址 memset(new, 0, size); new = (id)&((struct obj_layout *)new)[1]; } 去掉NSZone: struct obj_layout { NSUInteger retained; }; + (id) alloc { int size = sizeof(struct obj_layout) + size_of_the_object; struct obj_layout *p = (struct obj_layout *)calloc(1, size); return (id)(p + 1); }
retian:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为 1。指针的拷贝
- (id) retain { NSIncrementExtraRefCount(self); return self; } inline void NSIncrementExtraRefCount(id anObject) { if (((struct obj_layout *)anObject)[-1].retained == UINT_MAX - 1) [NSException raise: NSInternalInconsistencyExceptionformat: @"NSIncrementExtraRefCount() asked to increment too far"]; ((struct obj_layout *)anObject)[-1].retained++; }
release:通知内存释放这个对象,只有release才会真正释放内存。
- (void) release {if (NSDecrementExtraRefCountWasZero(self)) [self dealloc]; } BOOLNSDecrementExtraRefCountWasZero(id anObject) {if (((struct obj_layout *)anObject)[-1].retained == 0) { return YES; } else { ((struct obj_layout *)anObject)[-1].retained--; return NO; } }
nil:是把一个对象的指针置为空,切断了指针与内存中对象的联系;
release与nil 使用的先后顺序:
如果没有release就直接nil,那么虽然不会出错,却等于自己制造内存泄漏了,因为nil之后release就已经不起作用了。相反,如果在使用接口对象时只仅仅release没有设置self.objc =nil,那么程序可能也不会报错,但却会十分不稳定、不健壮,很容易发生崩溃现象。因为一个接口对象在release之后,给它所分配等内存就已经被释放了,如果释放之后系统再用到这个对象,那么程序就会crash。如果释放之后把它的指针置为空,则即便后面的程序用到该对象,也不会崩溃。
dealloc:众所周知,dealloc是非ARC情况下,调用dealloc是释放内存的。ARC环境下,也没有把dealloc函数禁掉,还是可以使用的,只不过不用调用[super dealloc]了。例如:页面中调用webview。
如果在WebView载入完成之前关闭画面的话,画面关闭后,ViewController也释放了。但由于WebView正在载入页面,而不会马上被释放,等到页面载入完毕后,回调delegate(ViewController)中的方法,由于此时ViewController已经被释放,所以会出错。
解决办法是在dealloc中把WebView的delegate释放。
-(void)dealloc {
self.webView.delegate = nil;
}
附录:
1、关于self的用法 找到一篇博客写的不错(http://blog.csdn.net/zhibudefeng/article/details/7714808)
主要是关于OC里面的getter、setter有关。self.object 与 myClass -> myObject来访问, 这样是直接访问对象本身
2、关于声明成IBOutlet属性:
在MRC中,IBOutlet本身就是retain 任何一个被声明为IBOutlet并且在Interface Builder里被连接到一个UI组件的成员变量,会被额外retain一次。所以使用了IBOutlet变量,一定要在dealloc/viewDidUnload里释放这个变量
在ARC中,我们使用IBOutlet属性都声明为weak。通过加载xib得到的用户界面,在其从xib文件加载时,就已经是view hierarchy的一部分了,而view hierarchy中的指向都是strong的。因此outlet所指向的UI对象不应当再被hold一次了
二、NSAutoreleasePool 的使用:
Apple's implementtation of autorelease in runtime/objc-arr.mm
class AutoreleasePoolPage {static inline void *push() {/* It corresponds to creation and ownership of an NSAutoreleasePool object */ } static inline void pop(void *token) {/* It corresponds to disposal of an NSAutoreleasePool object */ releaseAll(); } static inline id autorelease(id obj) {/* It corresponds to NSAutoreleasePool class method addObject. */ AutoreleasePoolPage *autoreleasePoolPage = /* getting active AutoreleasePoolPage object */ autoreleasePoolPage->add(obj); } id *add(id obj) {/* add the obj to an internal array; */ } void releaseAll() {/* calls release for all the objects in the internal array */ } }; void *objc_autoreleasePoolPush(void) {return AutoreleasePoolPage::push(); } void objc_autoreleasePoolPop(void *ctxt) {AutoreleasePoolPage::pop(ctxt); } id objc_autorelease(id obj) {return AutoreleasePoolPage::autorelease(obj); }
例如:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // equivalent to objc_autoreleasePoolPush() id obj = [[NSObject alloc] init]; [obj autorelease]; // equivalent to objc_autorelease(obj) [pool drain]; // equivalent to objc_autoreleasePoolPop(pool)
当drain 被调用的时候,会调用dealloc函数来释放pool的数组,在之前会先释放pool数组里面的所有object
-(void) drain { [self dealloc]; } -(void) dealloc { [self emptyPool]; [array release]; } -(void) emptyPool { for(id objc in array) { [objc release]; } }
在ARC与非ARC中,autoreleasepool的实现方式:
离开@autoreleasepool 的块,所有创建的对象都会自动释放