OC @Property属性

[TOC]

本质是什么

实际上@property = 实例变量 + get方法 + set方法。也就是说属性
@property name: setter方法+getter方法+_name

自动合成

定义一个property,在编译期间,编译器会生成实例变量,getter方法、setter方法,这些方法是通过自动合成(autosynthesize)的方式生成并添加到类中。
实际上,一个类经过编译后,会生成变量列表ivar_list,方法列表,method_list。每添加一个属性,在变量列表ivar_list会添加对应的变量,如_name,在方法列表method_list中会添加对应的setter和getter方法。

@synthesize name = _name;

手动合成

那么有自动合成,就有手动合成。
手动合成代码

@dynamic sex;

这样就告诉编译器,sex属性的实例变量,getter方法、setter方法都由开发者自己添加

//下面代码不添加,在使用该属性时候,程序会崩溃
@interface Student : NSObject
{
    NSString *_sex;
}

@property (nonatomic, copy) NSString *name;

@property (nonatomic, copy) NSString *sex;

@end

整体代码

@property (nonatomic,copy) NSString *name;///< name
@end

@implementation ViewController
/*
    两个一起写会报错,因为重写了get和set方法,编译器认为开发者想手动管理@property,此时会将@property作为@dynamic来处理
    因此也就不会自动生成变量。解决方法,显示的将属性和一个变量绑定:@synthesize name = _name;
    @synthesize name = _name;
*/
@synthesize name = _name;
- (void)setName:(NSString *)name{
    _name = name;
}

//get 不能使用self. 会造成死循环
-(NSString *)name{
    return _name;
//    return self.name;  // 错误的写法,会造成死循环

}

@property修饰符

  1. 修饰符的种类
    1. 原子性 -nonatomic, atomic
    2. 读写权限 -readwrite和readonly
    3. 内存管理 - assign,strong,weak,copy,unsafe_unretained
    4. set,get方法
  2. weak和assign的区别
    1. Weak修饰对象,对象释放后,引用计数为0,对象会被置为nil。
    2. assign修饰基本数据类型,如果用assign修饰对象,对象释放后,引用计数为0后,对象会变成野指针,容易崩溃。为什么基本数据类型不会,因为基本数据类型是在栈上面,不是在堆上面的。
  3. copy和strong
    1. 不可变使用copy,可变使用strong

不可变使用strong的例子

@property (nonatomic, strong) NSString *strongStr;
- (void)testStrCopy {
    NSString *tempStr = @"123";
    NSMutableString *mutString = [NSMutableString stringWithString:tempStr];
    self.strongStr = mutString;  // 子类初始化父类
    NSLog(@"self str = %p  mutStr = %p",self.strongStr,mutString);   // 两者指向的地址是一样的
    [mutString insertString:@"456" atIndex:0];
    NSLog(@"self str = %@  mutStr = %@",self.strongStr,mutString);  // 两者的值都会改变,不可变对象的值被改变
    /*
     self str = 0x281806520  mutStr = 0x281806520
     self str = 456123  mutStr = 456123
     */
}

可变使用copy的例子

@property (nonatomic, copy) NSMutableString *mutString;
- (void)testStrCopy {
    NSString *str = @"123";
    self.mutString = [NSMutableString stringWithString:str];
    /*
    // 首先声明一个临时变量 NSMutableString *tempString = [NSMutableString stringWithString:str]; 
    // 将该临时变量copy,赋值给self.mutString self.mutString = [tempString copy];
    通过[tempString copy]得到的self.mutString是一个不可变对象
    */
    NSLog(@"str = %p self.mutString = %p",str,self.mutString); // 两者的地址不一样
    [self.mutString appendString:@"456"]; // 会崩溃,因为此时self.mutArray是NSString类型,是不可变对象
}

可变对象的copy、mutableCopy,可以看到,只要是可变对象,无论是集合对象,还是非集合对象,copy和mutableCopy都是深拷贝。

- (void)testMutableCopy
{
    NSMutableString *str1 = [NSMutableString stringWithString:@"abc"];
    NSString *str2 = [str1 copy];
    NSMutableString *str3 = [str1 mutableCopy];
    NSLog(@"str1 = %p str2 = %p str3 = %p",str1,str2,str3);
    
    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"a",@"b", nil];
    NSArray *array2 = [array1 copy];
    NSMutableArray *array3 = [array1 mutableCopy];
    NSLog(@"array1 = %p array2 = %p array3 = %p",array1,array2,array3);
}

2018-12-13 19:12:44.287404+0800 testcopy[2654:1672606] str1 = 0x28020fba0 str2 = 0x92e1881c542bdf17 str3 = 0x28020f780
2018-12-13 19:12:44.287475+0800 testcopy[2654:1672606] array1 = 0x28020f8d0 array2 = 0x280c5e780 array3 = 0x28020fa20

不可变对象的copy、mutableCopy,不可变对象的copy是浅拷贝,mutableCopy是深拷贝。以NSString和NSArray为例,测试代码如下:

- (void)testCopy
{
    NSString *str1 = @"123";
    NSString *str2 = [str1 copy];
    NSMutableString *str3 = [str1 mutableCopy];
    NSLog(@"str1 = %p str2 = %p str3 = %p",str1,str2,str3);
    
    NSArray *array1 = @[@"1",@"2"];
    NSArray *array2 = [array1 copy];
    NSMutableArray *array3 = [array1 mutableCopy];
    NSLog(@"array1 = %p array2 = %p array3 = %p",array1,array2,array3);
}
2018-12-13 19:14:27.982467+0800 testcopy[2656:1673120] str1 = 0x102fc8078 str2 = 0x102fc8078 str3 = 0x280558f00
2018-12-13 19:14:27.982529+0800 testcopy[2656:1673120] array1 = 0x280b09ea0 array2 = 0x280b09ea0 array3 = 0x280558fc0

自定义对象如何支持copy:

自定义对象遵守NSCopying协议,且实现copyWithZone方法,NSCopying是系统方法,直接使用即可。

@interface Student : NSObject  
{ 
    NSString *_sex; 
} 
@property (atomic, copy) NSString *name; 
@property (nonatomic, copy) NSString *sex; 
@property (nonatomic, assign) int age; @end


- (instancetype)initWithName:(NSString *)name age:(int)age sex:(NSString *)sex
{
    if(self = [super init]){
        self.name = name;
        _sex = sex;
        self.age = age;
    }
    return self;
}

- (instancetype)copyWithZone:(NSZone *)zone
{
    // 注意,copy的是自己,因此使用自己的属性
    Student *stu = [[Student allocWithZone:zone] initWithName:self.name age:self.age sex:_sex];
    return stu;
}

输出

- (void)testStudent
{
    Student *stu1 = [[Student alloc] initWithName:@"Wang" age:18 sex:@"male"];
    Student *stu2 = [stu1 copy];
    NSLog(@"stu1 = %p stu2 = %p",stu1,stu2);
}
stu1 = 0x600003a41e60 stu2 = 0x600003a41fc0
//深复制,因为是内存复制,copyWithZone,而不是直接内存地址指向。

来源:iOS面试之@property

你可能感兴趣的:(OC @Property属性)