转载自:http://sofire.iteye.com/blog/1705149
MRR:Manual retain-release
推荐:《iPhone/Mac Objective-C内存管理教程和原理剖析》
http://www.cnblogs.com/VinceYuan/archive/2010/03/08/1680488.html
- 生成的对象,有一个引用计数:retainCount,当retainCount = 0,内存就会被释放
- 用alloc/new/copy生成对象时,其 retainCount = 1
- retain 让retainCount + 1,release让retainCount - 1,成对出现:[obj retain] [obj release]
- 用autorelease能让retainCount的管理简单些,涉及到autorelease pool
- 在生成新的RunLoop时,系统自动创建新的autorelease pool
property的修饰符:
- assign
- copy
- retain:参考默认实现,很重要
- 如:@property (retain) objA* obj;
retain、copy的默认实现:
-(void) setObjB:(ClassB*) value
{
if (objB != value)
{
[objB release]; //原来的对象会先release
objB = [value retain]; //copy类似
}
}
assign针对简单数据类型(scalar types) ,如int,float, CGRect, NSInteger等,它只是简单的赋值操作
copy/mutableCopy 浅拷贝和深拷贝
参考:《浅析ObjectiveC 深浅拷贝学习 》http://www.cocoachina.com/bbs/read.php?tid=80463
- 不可改变对象的copy,才是浅拷贝;其他都是深拷贝
- copy 返回的对象都是不可改变的
- 容器类(如NSArray等) 的内容都是浅拷贝的
内存泄露
参考:《Presentation: Finding & Fixing Mem Leaks》
http://www.streamingcolour.com/blog/2010/09/21/presentation-finding-fixing-mem-leaks/
常见情况1:
// @property (nonatomic, retain) MyClass* objA;
- (void)foo{
//retainCount = 2
self.objA = [[MyClass alloc] init];
}
- (void)dealloc{
//retainCount = 1
[objA release];
[super dealloc];
}
修复方法:
// @property (nonatomic, retain) MyClass* objA;
<!-- ^ Position is not set to relative / absolute here because of Mozilla -->
- (void)foo{
//retainCount = 1
MyClass *obj = [[MyClass alloc] init];
//retainCount = 2
self.objA = obj;
//retainCount = 1
[obj release]
}
- (void)dealloc{
//retainCount = 0
[objA release];
[super dealloc];
}
常见情况2:
<!-- ^ Position is not set to relative / absolute here because of Mozilla -->
// @property (nonatomic, retain) MyClass* objA;
- (void)foo{
MyClass *obj = [[MyClass alloc] init];
self.objA = obj;
[obj release];
//retainCount = 1
}
- (void)dealloc{
//retainCount = 1
[super dealloc];
}
<!-- ^ Position is not set to relative / absolute here because of Mozilla -->
修复方法:
// @property (nonatomic, retain) MyClass* objA;
- (void)foo{
MyClass *obj = [[MyClass alloc] init];
self.objA = obj;
[obj release];
//retainCount = 1
}
- (void)dealloc{
//retainCount = 0
[objA release];
[super dealloc];
}
self.abc = nil 与 _abc = nil的区别
@property (retain) classA *abc;
@synthesize abc = _abc;
需要明白 self.abc 的默认实现,它相当于:
[_abc release];
_abc = nil;
前者会发送release消息,而后者可能有内存泄露。
<!-- ^ Position is not set to relative / absolute here because of Mozilla -->
Tools
- Build & Analyze
- Leaks Instument
Automatic Reference Counting
- “Automatic Reference Counting (ARC) is a compiler-level feature that simplifies the process of managing object lifetimes (memory management) in Cocoa applications.”
- ARC is a pre-compilation step that adds retain/release/autorelease statements to your code for you
- 需要Xcode 4.2+, Apple LLVM 3.0+ compiler
简化了编程(本周上和MRR是一样的),不需要/不能使用下面这些方法
- retain /release
- autorelease
- retainCount
- NSAllocateObject / NSDeallocateObject
property的修饰符:
- strong:相当于retain
- weak:相当于assign
变量修饰符:
- __strong
- This means any object created usingalloc/init is retained for the lifetime of its current scope.
- is the default so you don’t need to type it.
- #相当于retain,在不再使用的时候被释放 (默认)
- __weak
- means the object can be destroyed at anytime.
- This is only useful if the object is somehow strongly referenced somewhere else.
- When destroyed, a variable with __weak is set to nil.
- #与assign很像,不同在于如果指向的数据被释放了,那么这个指向nil
- __unsafe_unretained
- is just like __weak but the poiner is not set to nil when the object is deallocated.
- Instead the pointer is left dangling (i.e. it no longer points to anything useful).
- #相当于assign,指向的数据如果被释放,这个指向原来的地址
- __autoreleasing
- not to be confused with calling autorelease on an object before returning it from a method, this is used for passing objects by reference, for example when passing NSError objects by reference such as [myObject performOperationWithError:&tmp];
- #标明传给函数的(id*)型参数是自动释放的,(函数中(id*)型参数默认的也是这种类型)
Toll-Free Bridging/CF和ObjC转换
- 在没有开启ARC时,可以进行强制转换.
- CFStringRef aCFString = (CFStringRef)aNSString;
- NSString *aNSString = (NSString *)aCFString;
- __bridge
-
简单赋值,不会影响两边对象的retain count.
id my_id;
CFStringRef my_cfref;
NSString *a = (__bridge NSString*)my_cfref;
CFStringRef b = (__bridge CFStringRef)my_id;
-
- __bridge_retained or CFBridgingRetain
- 保留赋值,赋值后也保留不释放右边的对象
- __bridge_transfer or CFBridgingRelease
- 释放赋值,赋值后释放右边的对象
- 例子
-
-(void)test
{
CFStringRef coreFoundationString = CFStringCreateWithCString(CFAllocatorGetDefault(),"C String", kCFStringEncodingUTF8); // 创建 retainCount = 1
id unknownObjectType = (__bridge id)coreFoundationString; // 简单赋值,不变,retainCount = 1
CFStringRef anotherString = (__bridge_retained CFStringRef)unknownObjectType; // 保留赋值,加一,retainCount = 2
NSString *objCString = (__bridge_transfer NSString *)coreFoundationString; // 释放赋值,减一,retainCount =1;由于NSString*默认strong,加一,retainCount = 2
NSLog(@"String = %@", objCString);
objCString = nil; // 不再指向原内存,原内存减一,retainCount = 1
CFRelease(anotherString); // 释放,减一,retainCount = 0
}
-
- 转换宏
-
#if __has_feature(objc_arc)
# define objc_retainedObject(o) ((__bridge_transfer id)(objc_objectptr_t)(o))
# define objc_unretainedObject(o) ((__bridge id)(objc_objectptr_t)(o))
# define objc_unretainedPointer(o) ((__bridge objc_objectptr_t)(id)(o))
#else
# define objc_retainedObject(o) ((id)(objc_objectptr_t)(o))
# define objc_unretainedObject(o) ((id)(objc_objectptr_t)(o))
# define objc_unretainedPointer(o) ((objc_objectptr_t)(id)(o))
#endif
-
@synthesize 和Dynamic ivars
@interface ClassA {
//NSObject _objB; // instance varible or ivar,可以不写,编译器会自动生成
}
@property (retain) NSObject *objB;
@end
@implement ClassA
@synthesize objB = _objB;
@end
<!-- ^ Position is not set to relative / absolute here because of Mozilla -->
@synthesize myProperty = myIvar; // a dynamic ivar named myIvar will be generated
@synthesize anotherProperty; // a dynamic ivar named anotherProperty will be generated
<!-- ^ Position is not set to relative / absolute here because of Mozilla -->
- @synthesize是新特征,简化setter/getter方法;
- 能用retain/copy/assing,strong/wak管理内存
- 在init和dealloc函数中,不建议用synthesized accessors,它会trigger KVO notifications;它本质上是setter/getter,在不需要调用setter/getter的时候,就不要用
- 32bit Mac OS X不支持Dynamic ivar,必须手动什么iVar,否则无法编译
- 调试原因(我还不清楚这是什么意思,因为在self变量里可以找到ivar):For some reason the XCode debugger doesn't show properties that don't have corresponding ivars explicitly declared.