您的位置:首页 > 移动开发 > Objective-C

iOS经典讲解之Objective-C属性的内存管理原理

2015-09-27 12:02 435 查看
@在进行讲解属性的内存管理之前,先来看看之前我们使用实例变量时是怎样管理内存的:

我们创建两个相关联的类Person类和Pet类,来看看它们中的赋值和取值方法是怎样管理内存的:

Pet.h

#import <Foundation/Foundation.h>

@interface Pet : NSObject
{
    
    NSString *_name;
}

// 声明赋值 取值方法
- (void)setName:(NSString *)name;
- (NSString *)name;

@end
Pet.m

#import "Pet.h"

@implementation Pet

// 实现赋值 取值方法
- (void)setName:(NSString *)name
{
    if (_name != name) {
        [_name release];
        // 字符串一般用copy
        _name = [name copy];
        
    }
    
}
- (NSString *)name
{
    return _name;
}

// 释放实例变量
-(void)dealloc
{
    [_name release];
    [super dealloc];
}

@end
Person.h

#import <Foundation/Foundation.h>
#import "Pet.h"

@interface Person : NSObject
{
    // 声明三个不同类型的实例变量
    Pet *_pet;
    NSString *_name;
    NSInteger _age;
}
// 声明赋值 取值方法
- (void)setPet:(Pet *)pet;
- (Pet *)pet;
- (void)setName:(NSString *)name;
- (NSString *)name;
- (void)setAge:(NSInteger)age;
- (NSInteger)age;
// 测试方法
- (void)test;

@end
Person.m

#import "Person.h"

@implementation Person

// 实现赋值 取值方法
- (void)setPet:(Pet *)pet
{
    if (_pet != pet) {
        [_pet release];
        // 对象类型使用retain获得所有权,然后在dealloc方法中释放
        _pet = [pet retain];
    }
}
- (Pet *)pet
{
    return _pet;
}
- (void)setName:(NSString *)name
{
    if (_name != name) {
        [_name release];
        // 字符串一般使用copy获得所有权,然后在dealloc方法中释放
        _name = [name copy];
    }
}
- (NSString *)name
{
    return _name;
    
}
- (void)setAge:(NSInteger)age
{
    // 基本数据类型不需要管理内存,因为不涉及引用计数的变化
    _age = age;
}
- (NSInteger)age
{
    return _age;
}
// 实现测试方法
- (void)test
{
    NSLog(@"%@:我今年%ld岁,我有只宠物叫%@", _name, _age, [_pet name]);
}
// 释放实例变量
-(void)dealloc
{
    [_name release];
    [_pet release];
    [super dealloc];
}

@end
接下来我们来看看属性是怎么写的:大家知道使用属性系统会自动声明并实现赋值(setter)和取值(getter)方法,不需要我们再来声明和实现赋值和取值方法,并且还自动给我们声明了带下划线的实例变量,给我们开发带来了极大的方便。虽然不需要我们再来操作赋值和取值方法,那他的实现原理我们还是要做到心中明白的。

属性是怎样管理内存的首先属性的语义控制类型:

语义控制:assign、copy、retain。assign一般用于非对象类型和代理(如int,
float等),retain(对象类型,如NSDictionary、NSArray)会使属性的引用计数加1,一般对象使用retain。copy如果想得到对象的副本,那么这个时候使用copy。默认是assign。

当使用assign时:就如同上面的对实例变量age的赋值方法

- (void)setAge:(NSInteger)age
{
    // 基本数据类型不需要管理内存,因为不涉及引用计数的变化
    _age = age;
}
当使用copy时,就如同上面的对实例变量name的赋值方法

- (void)setName:(NSString *)name
{
    if (_name != name) {
        [_name release];
        // 字符串一般使用copy获得所有权,然后在dealloc方法中释放
        _name = [name copy];
    }
}
当使用retain时就如同上面对实例变量pet的赋值方法

- (void)setPet:(Pet *)pet
{
    if (_pet != pet) {
        [_pet release];
        // 对象类型使用retain获得所有权,然后在dealloc方法中释放
        _pet = [pet retain];
    }
}
对于使用实例变量的代码用属性来替换的话,代码量缩短很多,下面替换上面的代码。

Pet.h

#import <Foundation/Foundation.h>

@interface Pet : NSObject

@property (nonatomic, retain) NSString *name;

@end
Pet.m

#import "Pet.h"

@implementation Pet

// 释放属性
-(void)dealloc
{
    [_name release];
    [super dealloc];
}

@end
Person.h

#import <Foundation/Foundation.h>
#import "Pet.h"

@interface Person : NSObject

@property (nonatomic, retain) Pet *pet;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;

// 测试方法
- (void)test;

@end
Person.m

#import "Person.h"

@implementation Person

// 实现测试方法
- (void)test
{
    NSLog(@"%@:我今年%ld岁,我有只宠物叫%@", _name, _age, [_pet name]);
}
// 释放属性
-(void)dealloc
{
    [_name release];
    [_pet release];
    [super dealloc];
}

@end
注意:如果使用属性,重写set和get方法时,系统会找不到相应的实例变量,这时需要重新声明实例变量,如果重写其中一个则不需要。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: