内存管理之属性参数与变量关键字
前言
自从Apple官方SDK中,引入了ARC
的概念后,在iOS开发时的内容管理变得不在是难题,原来的手动管理内容的工作全部交由编译器来做。
ARC(Atomic Reference Count),简述就是自动引入计数,而我们这篇文章主要叙述的也是Objective-C
语言中,影响“引用计数”的属性参数和变量关键字。
初始化实例
在没有引入ARC时,使用@property
关键字来生成属性的getters
与setters
方法,有几个可选的参数:assign
(默认),retain
,copy
。这几个参数主要影响的也是生成属性的setters方法。举例Person类有个属性为NSString类型的card,示例代码:1
2
31)Person person = [[Person alloc] init];
2)NSString *cardText = @"number";//@"number"堆内存地址:0X668901,引用计数为1,cardText指针地址:0X102221;
3)person.card = cardText;
assign
1 | @property (nonatomic, assign) NSString *card; |
assign参数,对于第三行的属性赋值来说就是简单赋值,不会更改”number”堆内存的引用计数,而且person.card指针的地址和cardText指针地址也是相同的。总结来说,就是一个简单地指针赋值。所以person.card的指针地址也是0X102221,指向的内存地址也是0X668901,而内存地址的引用计数仍然为1。
retain
1 | @property (nonatomic, retain) NSString *card; |
retain参数,对于第三行的属性赋值来说,就要释放掉person.card以前的内存值,而将开辟新的指针地址,来指向”number” 。所以person.card的指针地址将会变成新的地址,而指向的内容地址就是0X668901,而”number”堆内存的引用计数为2。
Copy
1 | @property (nonatomic, copy) NSString *card; |
顾名思义,copy参数,就是释放掉旧值,然后新建一块内存。对于第三行的赋值来说就是将”number”拷贝过去,所以person.card的指针地址将会变成新的地址,而person.card指向的堆内存地址也会变成新的地址,而”number”堆内存的引用计数仍然为1。这里额外说明一点,copy参数对于NSString类型的变量会拷贝堆内存的内容,而对于NSArray,NSDictionary等数据类型的变量时,拷贝的也是指针,就是我们所谓的“浅复制”。
ARC(weak、strong)
在Apple官方SDK引入ARC以后,我们就需要在ARC项目中,使用weak
和strong
参数来代替之前的参数,weak
就相当于之前的assign
,不同的是当weak类型的指针不使用一块堆内存时,weak类型的指针会置为nil,而较于之前使用assign的好处,就在于使用assign声明的指针不使用一块堆内存时,无法知道其他人是否还会使用,所以内存无法随着指针一起自动释放掉。strong
就相当于retain
,而默认的参数就是strong
,比如第二行的声明,cardText指针的类型也是strong类型。强引用和弱引用的区别就在于当一块堆内存没有任何强指针指向时,就会释放掉内存,并且清除掉所有的弱指针。在iOS开发中,唯一一种使用weak声明指针的情况,就是要避免“retain cycle”,也就是一个父类retain一个子类,而一个子类又retain了父类,造成内存无法释放。
block关键字
除了使用@property关键字声明属性时的几个参数可以影响内存管理之外,Objective-C语言也提供了一些关键字,来帮助我们管理一些局部变量:
- __strong 是缺省的关键词。
- __weak 声明了一个可以自动 nil 化的弱引用。
- __unsafe_unretained 声明一个弱应用,但是不会自动nil化,也就是说,如果所指向的内存区域被释放了,这个指针就是一个野指针了。
- __autoreleasing 用来修饰一个函数的参数,这个参数会在函数返回的时候被自动释放。