IOS下的ARC与MRC的区别与联系
一,ARC 和 MRC的区别概括?
MRC(MannulReference Counting)和ARC(Automatic Reference Counting)是Objective-c中提供了两种内存管理机制,分别提供对内存的手动和自动管理,来满足不同的需求。其实 ARC 内部机制原理也是来源于mrc ,arc 是在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 可以使用该机能。arc的首要目的就是让代码简洁化,编程简单化,开发更顺心应手,减少不必要的小问题小疏忽;顾名思义,自动引用计数管理,关于内存的申请,使用和释放过程都交给系统自动实现,我们可也不用关系里面的过程,但是事实上还是mrc的原理,只是是系统帮我们做了管理;MRC和ARC使用的编译器也不相同前者是GCC后者是LLVM3.0。
二,MRC的使用
MRC,手动引用计数器管理,是在我们申请到某一块内存,在使用之后,要手动释放,释放机理涉及到计数器问题,如果未释放内存,会造成内存的浪费,俗称内存泄露,甚至引起很多未知的错误结果,这对程序有威胁很大,但是,何时释放,怎么释放,注意哪些问题,很有讲究,这就是MRC的不便之处,也是苹果推出ARC的缘由;
MRC ,在代码上下形式主要表现为,调用该对象时,要做retain操作,使用完成后要release,最后还要重写dealloc方法,对该类的所有对象做释放,所以在mrc的代码会有autorelease,retain,release等词语,而arc不允许有这些词汇,应为这些操作都由系统自动完成。
MRC需要遵循的规则:
引用计数器
1.和内存管理相关的方法 1)alloc 引用计数器自动设为1 2)retain 引用计数器+1 返回了经过+1以后的当前实例对象 3)release 引用计数器-1,并不一定是释放 4)retainCount 获取引用计数器的值 5)dealloc 当实例对象被销毁之前,系统自动调用。 一定要调[super dealloc]
和内存管理相关的名词
1)僵尸对象:此对象被销毁,不能再使用,不能给它发送任何消息 2)野指针:指向僵尸对象(不可用的内存)的指针,给野指针发送消息将会产生不可控的后果。 3)空指针:没有指向任何对象的指针,给空指针发消息不会产生任何行为
内存管理原则
1.如果你想持有某个对象,就必须负责让做一次retain操作,引用计数器+1. 2.如果你想放弃对某个对象的持有权,就要负责让其做一次release操作,引用计数器-1. 3.谁retain,谁release。
三,ARC的使用
ARC,自动引用计数是一种编译器特性,提供对象的自动内存管理。ARC使得你可以专注于你的应用中的代码,UI以及对象之间的关系而不需要去关心使用retain、release去进行繁冗的内存管理。ARC通过增加编译时代码确保对象按需存在,按需释放。概念上来说,它与手动引用计数(MRC)遵从同样的规则:为你添加正确适当的内存管理代码。为了确保编译器生成正确的代码,ARC限制了你可以使用的方法和你使用toll-tree bridging的方式。Toll-free bridging,简称为TFB,是一种允许某些ObjC类与其对应的CoreFoundation类之间可以互换使用的机制。
ARC需要遵循的规则:
1 . 不能显式调用dealloc,retain,release,retainCount,autorelease,或者是使用@selector(retain),@selector(release)等等。但是你可以如果你需要释放一些资源而不是释放实例变量时,你可以实现dealloc,在dealloc函数里面去完成这些工作,但是记住,不要去调用,因为编译器会帮你做的。同时,dealloc函数里也不要去调用super dealloa,这也是编译器的工作。但是你可能需要在系统类和其他未使用ARC的代码中调用[systemClassInstance setDelegate:nil] ,同时你也需要使用CFRetain,CFRelease和其他CoreFoundation对象的相关方法。理解了Toll-free bridging你或许会清楚这个问题。 2 . 不能使用NSAllocateObject或者NSDeallocateObject。使用alloc创建对象,系统在运行时会关注对象的生存周期并在适当的时候释放他。 3 . 不能在C结构体中使用对象指针。如果你要使用结构体,还不如直接建立一个Objective-C对象来管理数据。 4 . id与void *之间不能随意的转换。你必须使用特定的类型转换告诉编译器对象的生命周期,在Objective-C对象与作为函数传入参数的CoreFoundation对象之间你需要做这样的转换。 5 . 不能使用NSAutoreleasePool自动释放池。ARC提供@autoreleasepool代替,并且比NSAutoreleasePool更高效。 6 . 不能使用内存区(memmory zons)。再也没有必要使用NSZone,因为现代的Objective-C运行时会忽略它。 7 . 不能以new为开头去命名一个访问器,这意味着你不能声明一个以new开头的property,除非你附给他一个不同名字的getter:
@property NSString *newTitle; //错误的 @property (getter=theNewTitle) NSString *newTitle; //正确的
ARC的编程方式
weak和strong是新引入的属性修饰符,例子如下: 1 @property(strong) MyClass *myObject; //强引用,同retain 2 @property(weak) MyClass *myObject; //弱引用,同assign,当所指向的对象被释放后被自动的置为nil 在ARC的工程中,strong是对象的默认属性,但是为了避免歧义最好还是显式的指明。
变量修饰符
__strong:缺省的修饰符,当对象有strong指针指向他时,他是不被释放的,alive。 __weak:保留对对象的弱引用指针,不增加引用计数,因此也对对象的生命周期没有保障,当所指向的对象被释放后自动置为nil。 __unsafe_unretained:保留对象的弱引用指针,当所指向的对象被释放后,该指针不会被置为nil,变成野指针。 __autoreleasing:修饰以引用(id *)传入的参数,并且当return后会被自动释放。主要用于引用传入参数。
变量修饰符的使用格式:
ClassName * qualifier variableName; 例如: MyClass * __weak myWeakReference; MyClass * __unsafe_unretained myUnsafeReference; 虽说编译器很伟大但偶尔也会小粗心一下,例如下面的错误就不会被报错,只是小警告,所以不要忽略警告哦~下面的例子是错误示例: NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]]; NSLog(@"string: %@", string); 虽然string在刚创建并初始化完成后使用,但是并没有一个强指针指向该对象,因此他一初始化完成就由于引用计数为0被释放了。结果输出的是null
ARC中如何避免循环引用?
你可以使用对象的生命周期修饰符来避免强引用循环而导致的互相引用内存不能被释放,从而造成内存泄露。例如,你可以设计一个父子对象图,父对象对子对象可以强引用strong,同时子对象对父对象的引用为弱类型的引用weak。
巧妙的使用weak弱引用是避免循环引用的良药,这就是通常为什么delegate为弱类型的原因。另外最容易循环引用的一块就是block内对自身的属性引用,这又是另外一块很重要的问题,将在后续的博客中单独作为一篇来讲解

浙公网安备 33010602011771号