本文主要是介绍ARC机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、ARC简介
ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的
retain、release、autorelease语句。开发者不再需要担心内存管理,因为编译器为你处理了一切
ARC 是编译器特性,而不是 iOS 运行时特性,它也不是类似于其它语言中的垃圾收集器。因此 ARC 和手动内
存管理性能是一样的,有时还能更加快速,因为编译器还可以执行某些优化
二、ARC原理
1、编译器如何自动管理内存
Clang编译器项目自带一个“静态分析器”,用于志明程序里应用计数出问题的地方,比如有Person类中有一个类方法
if(self == [Person Class])
{Person *p = [[self alloc] init];NSLog(@"%@",p);
}
else
{NSLog(@"%@是Person的子类",self);
}
由于if语句之外无法引用p,如果没有使用ARC机制,这段代码就会有内存泄漏,此时p对象内存中的计数器值为
1,因为没有相关语句来释放,所以这个对象会一直占据着它所在的内存空间。判定内存是否泄漏所用的规则很简
明:调用Person的alloc方法所返回的p对象的保留计数比期望值要多1,之后却没有与之对应的释放操作来抵消,计算
机可以将这些规则套用在程序上,从而分析出有内存泄漏问题的对象,“静态分析器”还可以根据需要,预先加入适当
的retain或release操作以避免内存泄漏的问题,自动引用计数正是源自于此。于是在前面那段代码的if语句结束之前,
可以于对象p上自动执行release操作,也就是把代码自动改写成以下形式:
if(self == [Person Class])
{Person *p = [[self alloc] init];NSLog(@"%@",p);[p release];
}
else
{NSLog(@"%@是Person的子类",self);
}
2、ARC对代码的优化
在编译期,ARC会把能够互相抵消的retain、release和autorelease操作约简,如果发现在同一个对象上执行了多
次保留和释放操作,那么ARC有时可以成对地移除这两个操作。比如有些方法在返回对象前执行了autorelease操作,
而调用方法地代码可能需要将返回地对象保留,例如在非ARC环境下有个初始化Person的类方法
+ (id)personWithAge:(int)age
{Person *p = [[[self alloc] init] autorelease];p.age = age;return p;
}>
假如当某个类里有个Person类的强引用成员变量_myPerson,当初始化该类时就可以有
<span style="font-size:18px;">_myPerson = [Person PersonWithAge:10];</span>
调用personWithAge方法会返回新的Person对象,而此方法在返回对象之前为其调用了autorelease方法,由于实例变
量_myPerson是个强引用,所以编译器在设置其值的时候还需要执行一次保留操作,因此,上面那句代码等价于下面
这段手工管理引用计数代码
Person *p = [Person personWithAge:10];
_myPerson = [p retain];
池回收对象时,p对象的引用计数值刚好执行完release之后降为0,那么该内存对象就会被回收,而_myPerson就会指
向一个僵尸对象。
此时应该能看出personWithAge方法里的autorelease和上段代码中的retain操作时多余的,为提升性能,可以将
二者删去。
当ARC在运行期检测到这一对多余的操作时,也就是autorelease其后紧跟着retain,为了优化代码,在方法中返
回自动释放的对象时会执行一个特殊的函数,此时不直接调用对象的autorelease方法,而改为调用
objc_autoreleaseReturnValue。此函数会检视当前方法返回之后即将要执行的那段代码,若发现那段代码要在返回的
对象上执行retain操作,则设置全局数据结构中的一个标志位,而不执行autorelease操作。与之相似,如果方法返回
了一个自动释放的对象,而调用方法的代码要保留此对象,那么此时不执行retain,而是执行
objc_retainAutoreleaseReturnValue函数,此函数要检测刚才提到的那个标志位,若已置位,则不执行retain操作,设
置并检测标志位要比autorelease和retain更快。下面这段代码演示类ARC是如何优化程序的
在ARC编译环境下,对于Person类中的初始化的类方法
+ (id)personWithAge:(int)age
{Person *p = [[[self alloc] init] autorelease];p.age = age;objc_autoreleaseReturnValue(p);
}
而使用该方法时
<span style="font-size:18px;">Person *p = [Person personWithAge:10];
_myPerson = objc_retainAutoreleaseReturnValue(p);</span>
为了得到最佳效率,这些特殊函数得实现代码都会因处理器而异,下面得伪代码演示了这一步骤
id objc_autoreleaseReturnValue(id object)
{if(/*后面的代码有一次retain操作*/){set_flag(object);return object; // 不会再进行autorelease操作}else{return [object autorelease];}
}id objc_retainAutoreleaseReturnValue(id object)
{if(get_flag(object)) // 即该retain操作前有autorelease{clear_flag(object);return object; // 不再进行retain操作}else{return [object retain];}
}
只有编译器的开发者能实现此函数了。
三、ARC的使用
1、规则
ARC的规则非常简单,只要还有一个强指针指向对象,对象就会保持再内存中。
2、强指针和弱指针
默认所有实例变量和局部变量都是强指针;
弱指针指向的对象被回收后,弱指针会自动变成nil指针,不会引发野指针错误
3、使用注意
(1)不能调用release、retain、autorelease、retainCount、copy
(2)可以重写dealloc,但是不能调用[super dealloc]
(3)@property : 想长期拥有某个对象,应该用strong,其他对象用weak
(4)其他基本数据类型依然用assign
(5)两端互相引用时,一端用strong、一端用weak
代码示例:
#import <Foundation/Foundation.h>
@class Person;@interface Dog : NSObject
//谨记:@property后面跟着分号;
@property (nonatomic,strong) Person *person;
@end#import "Dog.h"@implementation Dog
- (void)dealloc
{NSLog(@"Dog is dealloc");// [super dealloc]; 不需要再调用了}
@end/*strong:表示该变量引用的是强指针(默认)weak:表示该变量引用的是弱指针(多用于对象循环引用)*/#import "Person.h"
//谨记:@class 类名;,后面跟分号;
@class Dog;@interface Person : NSObject@property (nonatomic,assign) int age;
//强指针类型
//@property (nonatomic,strong) Dog *dog;
//使用弱指针,当main函数执行完会先回收局部变量,因为指向够的指针是弱指针,所以狗对象会被释放,狗对象被释放之后里面的成员变量person也不存在了所以就不会指向person,所以person也会被释放
@property (nonatomic,weak) Dog *dog;@end#import "Person.h"@implementation Person
- (void) dealloc
{NSLog(@"age = %d Person---dealloc",_age);
}
@end/*指针:强指针:默认情况下,所有指针都是强指针 __strong弱指针:__weak,弱指针指向的对象会被回收*/
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Dog.h"
int main()
{Person *p = [[Person alloc] init];Dog *d = [[Dog alloc] init];p.age = 10;/*当两个成员变量都是强指针且循环引用,则两个强指针一直互相指向则arc机制不会释放对象。p.dog = d;d.person = p;*/return 0;
}
这篇关于ARC机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!