旧时代MRC(-fno-objc-arc)
Objective-C内存管理叫引用计数(Reference Counting)xtransfer, 当一个新建实例RC=1, retain操作RC加1, release操作,RC减1。 一旦RC等于0, 实例被销毁,你无法再retain抢救回来
NSObject*testObject=[[NSObjectalloc]init];NSLog(@"%p",&testObject);[testObjectrelease];[testObjectretain];NSLog(@"%@",[testObjectdeion]);[testObjectclass];
运气好,你能编译执行过,但是强烈不推荐这样做.
MRC经常会出现,错误实例release, 或者release过度xtransfer的情况,直接导致程序崩溃。
还有就是MRC暴露的NSAutoreleasePool对象,如果调用[pool autorelease], 会产生NSInvalidArgumentException
ARC时代(-fobjc-arc)
By enabling ARC with the new Apple LLVM compiler, you will never need to type retain or release again, dramatically simplifying the development process, while reducing crashes and memory leaks. The compiler has a complete understanding of your objects, and releases each object the instant it is no longer used, so apps run as fast as ever, with predictable, smooth performance.
从Xcode4.2起, ARC作为默认选项。ARC把MRC时代的reretain, release交给编译器。并简化了代码,减少潜在出错的可能性。
循环引用
在iOS5或者OSX Lion之后,可以用__weak关键字,来打破这样的循环引用,如果之前,可以用__unsafe_unretained
id__strongobj0=[[NSObjectalloc]init];id__weakobj1=obj0;
__weak关键字
2个无文档开放API, runtime调用,如果函数内包含runtime代码可能会死锁。
//是否允许使用__weak, 如果NO, 在使用__weak时SIGABRT崩溃- (BOOL)allowsWeakReference UNAVAILABLE_ATTRIBUTE;//是否允许使用__weak, 如果NO, 对象无法访问- (BOOL)retainWeakReference UNAVAILABLE_ATTRIBUTE;
__weak关键字在运行时主要调用objc_initWeak和objc_destroyWeak, 可以看下两个函数都调用了storeWeak, 在weak结束使用时,objc_destroyWeak传入nil值,并在StripedMap中将对应地址的指向为nil
idobjc_initWeak(id*location,idnewObj){if(!newObj){*location=nil;returnnil;}returnstoreWeak<DontHaveOld,DoHaveNew,DoCrashIfDeallocating>(location,(objc_object*)newObj);}voidobjc_destroyWeak(id*location){(void)storeWeak<DoHaveOld,DontHaveNew,DontCrashIfDeallocating>(location,nil);}
通常,__weak关键字除了objc_initWeak和objc_destroyWeak之外,相当于__strong加上autoreleasepool。这样能够保证接下来的函数执行后,再释放掉对象。
好的习惯是减少__weak的使用,这样会减少objc_initWeak, objc_destroyWeak, storeWeak的调用次数,基本上都是为了解决循环引用问题。__weak声明后通常会再用__strong转变一下。
第一,可以减少对象重复加入autoreleasepool。
第二,也能够保证多线程的时候,在进入执行前,__strong能够阻止中途被释放掉的情况。例如AFNetworking
id__weakobj1=obj;[obj1deion];idtmp=objc_loadWeakRetained(&obj1);objc_autorelease(tmp);
__autorelease关键字
ARC下我们无法调用NSAutoreleasePool, autorelease,取而代之的是可以用 @autoreleasepool {}, __autoreleasing,但实际使用中,甚至__autoreleasing也很少用到。编译器会检查函数调用赋值情况,以及函数名是否一个函数带有alloc/new/copy/mutableCopy,如果没有,会自动加入到autoreleasePool中。
另一种情况是__weak指向的变量,会自动加入到autoreleasePool中。
还有一种就是id * (例如NSError **),也会自动加入到autoreleasePool中。
# 编译出错NSError*error=nil;NSError**pError=&error;
当赋值pointer的时候,ARC关键字必须一样
NSError*error0=nil;NSError*__strong*pError0=&error0;NSError__weak*error1=nil;NSError*__weak*pError1=&error1;NSError__unsafe_unretained*error2=nil;NSError*__unsafe_unretained*pError2=&error2;NSError__autoreleasing*error3=nil;NSError*__autoreleasing*pError3=&error3;
C++/C与ARC
如果你要在struct中,使用id,你需要使用__unsafe_unretained安抚编译器。
structData{NSMutableArray__unsafe_unretained*array;};
相关测试代码
在ARC中id和void *之间,必须使用到转换, __bridge可以使其转换
-(void)testBridgeCasting{idarray=[[NSMutableArrayalloc]init];//strong +1CFMutableArrayRefcfArray=(__bridgeCFMutableArrayRef)array;//do nothingCFShow(cfArray);XCTAssertEqual(CFGetRetainCount(cfArray),1);XCTAssertEqual(_objc_rootRetainCount(array),1);}//array -1
CoreFoundation和Foundation中很多的Object区别非常少,例如一个由Foundation创建的object,可以由CoreFoundation释放,反之亦然。
NS_INLINECF_RETURNS_RETAINEDCFTypeRef_NullableCFBridgingRetain(id_NullableX){return(__bridge_retainedCFTypeRef)X;}NS_INLINEid_NullableCFBridgingRelease(CFTypeRefCF_CONSUMED_NullableX){return(__bridge_transferid)X;}
__bridge_retained
-(void)testBridgeRetainCasting{idarray=[[NSMutableArrayalloc]init];//strong +1CFMutableArrayRefcfarry_normal=(__bridgeCFMutableArrayRef)array;//do nothingXCTAssertEqual(CFGetRetainCount(cfarry_normal),1);XCTAssertEqual(_objc_rootRetainCount(array),1);CFMutableArrayRefcfArray_retain=(__bridge_retainedCFMutableArrayRef)array;// retain +1XCTAssertEqual(CFGetRetainCount(cfArray_retain),2);XCTAssertEqual(_objc_rootRetainCount(array),2);CFRelease(cfArray_retain);}//array -1
__bridge_transfer
-(void)testBridgeTransferCasting{CFMutableArrayRefcfArray=CFArrayCreateMutable(kCFAllocatorDefault,0,NULL);// +1XCTAssertEqual(CFGetRetainCount(cfArray),1);NSMutableArray*array=(__bridgeNSMutableArray*)cfArray;//strong +1XCTAssertEqual(CFGetRetainCount(cfArray),2);XCTAssertEqual(_objc_rootRetainCount(array),1);[arraydeion];array=(__bridge_transferNSMutableArray*)cfArray;// strong 放弃原值 -1 strong 加入新值 +1 transfer -1XCTAssertEqual(CFGetRetainCount(cfArray),1);XCTAssertEqual(_objc_rootRetainCount(array),1);[arraydeion];}// array -1
测试工具
extern void _objc_autoreleasePoolPrint(); //这是个私有APIextern int _objc_rootRetainCount(id); //这是个私有API
来源链接:https://blog.mogoal.com/2014/10/18/objective-c-memory-learning/
程序员共读整理发布,转载请联系作者获得授权