内存管理(二):copy、retain、assign

在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


1.3 可变类型

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值