在OC中,我们只对alloc、copy、retain(自己写的)进行内存管理,其他的不用管理
1. copy
所有遵循于NSCopying协议的类,都可以使用copy:
NSString、NSNumber、NSArray、NSDictionary
NSValue
1.1 字符串
NSString *str = @"hello";
NSString *str1 = [str copy];
NSLog(@"str = %p, str1 = %p", str, str1);// %p:打印地址;str:打印堆的地址,&str:打印栈的地址
NSLog(@"retainCount: str = %ld, str1 = %ld", [str retainCount], [str1 retainCount]);// 字符串的引用计数为-1
%p:打印地址
str:打印堆的地址,&str:打印栈的地址
打印结果:
str = 0x100002048, str1 = 0x100002048
retainCount: str = -1, str1 = -1
1.2 不可变类型
NSArray *arr = [NSArray arrayWithObjects:@"1", @"2", nil];
NSArray *arr1 = [arr copy];
NSLog(@"arr= %p, arr1 = %p", arr, arr1);
NSLog(@"retainCount: arr = %ld, arr1 = %ld", [arr retainCount], [arr1 retainCount]);
在系统中,对不可变类型使用copy,其效果类似于retain
不可变:一旦使用copy,会在原有的(arr)引用计数+1
打印结果:
arr= 0x1004008b0, arr1 = 0x1004008b0
retainCount: arr = 2, arr1 = 2
NSMutableArray *mArr = [NSMutableArray arrayWithObjects:@"1", @"2", nil];
NSMutableArray *mArr1 = [mArr copy];
NSLog(@"mArr= %p, mArr1 = %p", mArr, mArr1);
NSLog(@"retainCount: mArr = %ld, mArr1 = %ld", [mArr retainCount], [mArr1 retainCount]);
// [mArr1 addObject:str];
// 可变对象要想在拷贝后得到可变的对象,要用mutableCopy进行拷贝
NSMutableArray *mArr2 = [mArr mutableCopy];
[mArr2 addObject:str];
可变对象被拷贝,返回的是不可变对象
可变:一旦使用copy,会在结果上的(mArr1)引用计数+1
可变对象要想在拷贝后得到可变的对象,要用mutableCopy进行拷贝
打印结果:
mArr= 0x100400d60, mArr1 = 0x100401810
retainCount: mArr = 1, mArr1 = 1
例子:
Person.h文件
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *str;
@property (nonatomic, copy) NSMutableArray *mArr;
@end
Person.m文件
#import "Person.h"
@implementation Person
- (void)dealloc
{
[_str release];
[_mArr release];
[super dealloc];
}
- (instancetype)init
{
self = [super init];
if (self) {
self.mArr = [NSMutableArray array];
}
return self;
}
// 声明属性时,(nonatomic, xx)中xx是啥,系统的setter方法中就用啥
- (void)setMArr:(NSMutableArray *)mArr
{
if (_mArr != mArr) {
[_mArr release];
// 系统的写法是_mArr = [mArr copy];
_mArr = [mArr retain];
}
}
@end
main中
Person *p = [[Person alloc] init];
// @property (nonatomic, copy) NSMutableArray *mArr;
// 重写setter方法,管理内存,程序不会蹦
[p.mArr addObject:@"1"];
2. assign
Person.h文件
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, assign) NSMutableDictionary *mDic;
@end
Person.m文件
#import "Person.h"
@implementation Person
- (void)dealloc
{
// assign,在dealloc中不能释放(释放会出现野指针)
// [_mDic release];
[super dealloc];
}
// 系统的写法
- (void)setMDic:(NSMutableDictionary *)mDic
{
_mDic = mDic;
}
@end
不引起引用计数的改变,在dealloc中不能释放(释放会出现野指针)
基础类型变量都用assign,因为它没有办法retain
拓展
1. 如果在数组或字典中添加一个元素,那么这个元素的引用计数+1(保证数组或字典在使用元素时安全)
Person *p1 = [[Person alloc ] init];
NSLog(@"p1.retainCount1 = %ld", [p1 retainCount]);
NSArray *array = [NSArray arrayWithObjects:p1, nil];
NSLog(@"p1.retainCount = %ld", [p1 retainCount]);
打印结果:
p1.retainCount = 1
p1.retainCount = 2
2. 如果在数组或字典中移除一个元素,那么这个元素的引用计数-1,数组或字典释放时,其中的元素也一一释放掉
<pre name="code" class="objc">Person *p2 = [[Person alloc ] init];
NSLog(@"p2.retainCount = %ld", [p2 retainCount]);
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:p2, nil];
NSLog(@"p2.retainCount = %ld", [p2 retainCount]);
[mArray removeObject:p2];
NSLog(@"p2.retainCount = %ld", [p2 retainCount]);
打印结果:
p2.retainCount = 1
p2.retainCount = 2
p2.retainCount = 1