[TOC]
本質(zhì)是什么
實(shí)際上@property = 實(shí)例變量 + get方法 + set方法度陆。也就是說(shuō)屬性
@property name: setter方法+getter方法+_name
自動(dòng)合成
定義一個(gè)property岩臣,在編譯期間巨坊,編譯器會(huì)生成實(shí)例變量,getter方法悍募、setter方法茧彤,這些方法是通過(guò)自動(dòng)合成(autosynthesize)的方式生成并添加到類(lèi)中。
實(shí)際上继准,一個(gè)類(lèi)經(jīng)過(guò)編譯后枉证,會(huì)生成變量列表ivar_list,方法列表移必,method_list室谚。每添加一個(gè)屬性,在變量列表ivar_list會(huì)添加對(duì)應(yīng)的變量崔泵,如_name秒赤,在方法列表method_list中會(huì)添加對(duì)應(yīng)的setter和getter方法。
@synthesize name = _name;
手動(dòng)合成
那么有自動(dòng)合成憎瘸,就有手動(dòng)合成入篮。
手動(dòng)合成代碼
@dynamic sex;
這樣就告訴編譯器,sex屬性的實(shí)例變量幌甘,getter方法潮售、setter方法都由開(kāi)發(fā)者自己添加
//下面代碼不添加,在使用該屬性時(shí)候锅风,程序會(huì)崩潰
@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
/*
兩個(gè)一起寫(xiě)會(huì)報(bào)錯(cuò)酥诽,因?yàn)橹貙?xiě)了get和set方法,編譯器認(rèn)為開(kāi)發(fā)者想手動(dòng)管理@property皱埠,此時(shí)會(huì)將@property作為@dynamic來(lái)處理
因此也就不會(huì)自動(dòng)生成變量肮帐。解決方法,顯示的將屬性和一個(gè)變量綁定:@synthesize name = _name;
@synthesize name = _name;
*/
@synthesize name = _name;
- (void)setName:(NSString *)name{
_name = name;
}
//get 不能使用self. 會(huì)造成死循環(huán)
-(NSString *)name{
return _name;
// return self.name; // 錯(cuò)誤的寫(xiě)法边器,會(huì)造成死循環(huán)
}
@property修飾符
- 修飾符的種類(lèi)
- 原子性 -nonatomic, atomic
- 讀寫(xiě)權(quán)限 -readwrite和readonly
- 內(nèi)存管理 - assign训枢,strong,weak忘巧,copy恒界,unsafe_unretained
- set,get方法
- weak和assign的區(qū)別
- Weak修飾對(duì)象砚嘴,對(duì)象釋放后仗处,引用計(jì)數(shù)為0眯勾,對(duì)象會(huì)被置為nil。
- assign修飾基本數(shù)據(jù)類(lèi)型婆誓,如果用assign修飾對(duì)象吃环,對(duì)象釋放后,引用計(jì)數(shù)為0后洋幻,對(duì)象會(huì)變成野指針郁轻,容易崩潰。為什么基本數(shù)據(jù)類(lèi)型不會(huì)文留,因?yàn)榛緮?shù)據(jù)類(lèi)型是在棧上面好唯,不是在堆上面的。
- copy和strong
- 不可變使用copy燥翅,可變使用strong
不可變使用strong的例子
@property (nonatomic, strong) NSString *strongStr;
- (void)testStrCopy {
NSString *tempStr = @"123";
NSMutableString *mutString = [NSMutableString stringWithString:tempStr];
self.strongStr = mutString; // 子類(lèi)初始化父類(lèi)
NSLog(@"self str = %p mutStr = %p",self.strongStr,mutString); // 兩者指向的地址是一樣的
[mutString insertString:@"456" atIndex:0];
NSLog(@"self str = %@ mutStr = %@",self.strongStr,mutString); // 兩者的值都會(huì)改變,不可變對(duì)象的值被改變
/*
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];
/*
// 首先聲明一個(gè)臨時(shí)變量 NSMutableString *tempString = [NSMutableString stringWithString:str];
// 將該臨時(shí)變量copy骑篙,賦值給self.mutString self.mutString = [tempString copy];
通過(guò)[tempString copy]得到的self.mutString是一個(gè)不可變對(duì)象
*/
NSLog(@"str = %p self.mutString = %p",str,self.mutString); // 兩者的地址不一樣
[self.mutString appendString:@"456"]; // 會(huì)崩潰,因?yàn)榇藭r(shí)self.mutArray是NSString類(lèi)型森书,是不可變對(duì)象
}
可變對(duì)象的copy靶端、mutableCopy,可以看到,只要是可變對(duì)象凛膏,無(wú)論是集合對(duì)象杨名,還是非集合對(duì)象,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
不可變對(duì)象的copy台谍、mutableCopy,不可變對(duì)象的copy是淺拷貝,mutableCopy是深拷貝吁断。以NSString和NSArray為例趁蕊,測(cè)試代碼如下:
- (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
自定義對(duì)象如何支持copy:
自定義對(duì)象遵守NSCopying協(xié)議,且實(shí)現(xiàn)copyWithZone方法仔役,NSCopying是系統(tǒng)方法掷伙,直接使用即可。
@interface Student : NSObject <NSCopying>
{
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
//深復(fù)制赃泡,因?yàn)槭莾?nèi)存復(fù)制寒波,copyWithZone,而不是直接內(nèi)存地址指向升熊。
來(lái)源:iOS面試之@property