iOS 学习日志(3)--关于Automatic Reference Counting

1、关于Alloc Retain Release 等web

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。指针的拷贝app

- (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 使用的前后顺序:ui

若是没有release就直接nil,那么虽然不会出错,却等于本身制造内存泄漏了,由于nil以后release就已经不起做用了。相反,若是在使用接口对象时只仅仅release没有设置self.objc =nil,那么程序可能也不会报错,但却会十分不稳定、不健壮,很容易发生崩溃现象。由于一个接口对象在release以后,给它所分配等内存就已经被释放了,若是释放以后系统再用到这个对象,那么程序就会crash。若是释放以后把它的指针置为空,则即使后面的程序用到该对象,也不会崩溃。spa

dealloc:众所周知,dealloc是非ARC状况下,调用dealloc是释放内存的。ARC环境下,也没有把dealloc函数禁掉,仍是可使用的,只不过不用调用[super dealloc]了。例如:页面中调用webview。.net

若是在WebView载入完成以前关闭画面的话,画面关闭后,ViewController也释放了。但因为WebView正在载入页面,而不会立刻被释放,等到页面载入完毕后,回调delegate(ViewController)中的方法,因为此时ViewController已经被释放,因此会出错。指针

解决办法是在dealloc中把WebView的delegate释放。code

-(void)dealloc {

    self.webView.delegate = nil;

}

附录:

一、关于self的用法 找到一篇博客写的不错(http://blog.csdn.net/zhibudefeng/article/details/7714808)

主要是关于OC里面的getter、setter有关。self.object 与 myClass -> myObject来访问, 这样是直接访问对象自己

二、关于声明成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一次了

2、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 的块,全部建立的对象都会自动释放

相关文章
相关标签/搜索