MRC與ARC
談property屬性之前需要引入OC的兩種內(nèi)存管理機(jī)制
MRC:全稱Manual Reference Counting 即手動(dòng)引用計(jì)數(shù)器
ARC:全稱Automatic Reference Counting 即自動(dòng)引用計(jì)數(shù)器叮阅,
自從ARC在iOS5被引入后椭蹄,經(jīng)過多個(gè)版本的驗(yàn)證蕉堰,MRC目前已經(jīng)成為了歷史加勤,下文將主要講解ARC下的關(guān)鍵字
Property屬性含有以下修飾符
- 原子性:nonatomic赞季,atomic
- 讀寫:readwrite, readonly, writeonly
- 內(nèi)存:weak,assign翰守,unsafe_unretained则吟,strong,retain皇忿,copy畴蹭,
atomic vs nonatomic
atomic
- 默認(rèn)關(guān)鍵字
- 對對象操作屬于原子性,即只有一個(gè)線程可以同時(shí)訪問這個(gè)實(shí)例鳍烁,是線程安全的
- 實(shí)際上使用頻率很低叨襟,因?yàn)槠涫褂猛芥i,開銷較大幔荒,損失性能
nonatomic:
- 對對象操作屬于非原子性糊闽,實(shí)例可以被多個(gè)線程訪問,所以無法保證多線程狀態(tài)下的安全性爹梁,屬于非線程安全
- 效率要比atomic高
- 在iOS開發(fā)中被廣泛使用
readwrite VS readonly VS writeonly
readwrite
- 默認(rèn)屬性
- 自動(dòng)生成setter右犹,getter方法
- 讀寫屬性,可以對實(shí)例進(jìn)行讀寫
readonly
- 自動(dòng)生成getter方法
- 只讀屬性卫键,只能對實(shí)例進(jìn)行讀取
writeonly
- 自動(dòng)生成setter方法 從來沒用過
- 只寫屬性傀履,只能對實(shí)例進(jìn)行寫入
自定義getter虱朵,setter方法
getter=<name>
setter=<name>
@interface ViewController ()
@property(strong,readonly,getter=gA)NSString *A;
@property(strong,getter=gB,setter=sB:)NSString *B;
@property (strong,getter=gC)NSString *C;
@property NSString *D;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_A = @"A";
NSLog(@"A:%@",[self gA]);
[self sB:@"B"];
NSLog(@"B:%@",[self gB]);
[self setC:@"C"];
NSLog(@"C:%@",[self gC]);
[self setD:@"D"];
NSLog(@"D:%@",[self D]);
// Do any additional setup after loading the view.
}
@end
assign VS weak VS unsafe_unretained
- assign 可以修飾基本數(shù)據(jù)類型莉炉,也可以修飾引用類型
- weak 用于修飾引用類型
- unsafe_unretained 用于修飾引用類型
同
- 三者都可以修飾引用類型
- 都為弱引用,即不增加引用計(jì)數(shù)器計(jì)數(shù)
異
- assign常用于修飾基本數(shù)據(jù)類型碴犬,修飾對象時(shí)絮宁,當(dāng)對象釋放,指針不會(huì)置空服协,會(huì)生成野指針绍昂,向?qū)ο蟀l(fā)送消息會(huì)引發(fā)崩潰
- weak修飾引用類型,當(dāng)對象釋放后偿荷,指針會(huì)被設(shè)置為nil窘游,向?qū)ο蟀l(fā)送消息不會(huì)引發(fā)崩潰
- unsafe_unretained與assign的區(qū)別在于,其只修飾引用類型跳纳,也會(huì)生成野指針
為什么UI控件和delegate用weak
- 當(dāng)控制器持有的view addsubView時(shí)候會(huì)強(qiáng)引用subview忍饰,所以修飾subview時(shí)使用weak就可以了
- delegate同理,拿tableview舉例寺庄,addsubview時(shí)控制器已經(jīng)強(qiáng)引用了tableview艾蓝,如果tableview的delegate還用strong力崇,則會(huì)造成循環(huán)引用
strong VS retain VS copy
- strong 用于引用類型,強(qiáng)引用赢织,引用計(jì)數(shù)器+1亮靴, strong 用于ARC,retain用于MRC于置,默認(rèn)屬性
- retain 用于引用類型茧吊,強(qiáng)引用,引用計(jì)數(shù)器+1俱两,retain用于MRC
- copy 會(huì)在內(nèi)存中拷貝對象饱狂,分為深拷貝,淺拷貝
驗(yàn)證下strong是否為默認(rèn)屬性
@interface ViewController ()
@property(nonatomic,weak)Person *s;
@property(nonatomic)Person *p;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *temp = [Person new];
self.s = temp;
self.p = temp;
temp = nil;
NSLog(@"對象內(nèi)存地址:%p %p",_s,_p);
_p = nil;
NSLog(@"對象內(nèi)存地址:%p %p",_s,_p);
// Do any additional setup after loading the view.
}
@end
結(jié)論:temp置空宪彩,s休讳,p仍舊存在,即引用計(jì)數(shù)器已+1尿孔,
p置空后俊柔,s也為空,因?yàn)閟是weak活合,若引用
copy的深拷貝與淺拷貝
當(dāng)copy修飾不可變類型對象時(shí)雏婶,如NSString,NSDictionary白指,NSArray留晚,其實(shí)發(fā)生的是淺拷貝,即copy = strong
NSString *temp = @"FFF";
NSString *str = [temp copy];//淺拷貝告嘲,兩個(gè)指針指向同一塊內(nèi)存空間
NSLog(@"%p %p",temp,str);//0x102924078 0x102924078
NSLog(@"%@ %@",temp,str);//FFF FFF
temp = @"TTT";//temp指向的內(nèi)存空間發(fā)生改變错维,str仍舊指向FFF的內(nèi)存空間
NSLog(@"%p %p",temp,str);//0x1029240d8(改變) 0x102924078
NSLog(@"%@ %@",temp,str);//TTT FFF
當(dāng)copy修飾可變類型對象時(shí),如NSMutableString橄唬,NSMutableArray赋焕,NSMutableDictionary,發(fā)生的單層深拷貝仰楚,其他層淺拷貝
Person *person = [Person new];
person.age = @"16";
NSMutableArray <Person *>*temp = [NSMutableArray arrayWithObjects:person, nil];
NSMutableArray <Person *>*arr = [temp copy];//數(shù)組拷貝隆判,內(nèi)部對象淺拷貝
NSLog(@"%p %p",temp,arr);//0x60000350b630 0x60000397c740,數(shù)組對象發(fā)生了深拷貝
NSLog(@"%@ %@",temp,arr); // <Person: 0x60000397c720> <Person: 0x60000397c720> 數(shù)組內(nèi)的對象發(fā)生了淺拷貝
NSLog(@"%@ %@",temp[0].age,arr[0].age);//16 16
person.age = @"18";
NSLog(@"%@ %@",temp[0].age,arr[0].age);//18 18 因?yàn)闇\拷貝,所以Person對象發(fā)生改變后僧界,所有數(shù)組內(nèi)的值都發(fā)生了改變
Person *crash = [Person new];
crash.age = @"19";
[temp addObject:crash];
NSLog(@"%ld %ld",temp.count,arr.count);//2 1 數(shù)組發(fā)生變化
[arr addObject:crash];//會(huì)崩潰侨嘀,因?yàn)閏opy出的數(shù)組對象為不可變的數(shù)組,NSMutableDictionary捂襟,NSMutableString同理
建議用copy修飾有對應(yīng)可變類型子類的對象
NSString/NSMutableString,NSArray/NSMutableArray,NSDictionary/NSMutableDictionary
@interface Person : NSObject
@property(nonatomic, strong)NSString *age;
@end
Person *person = [Person new];
NSMutableString *s = [[NSMutableString alloc] initWithString:@"A"];
//將可變字符串賦值給age
person.age = s;
//輸出的地址和內(nèi)容均一致
NSLog(@"%p %p %@ %@", person.age, s, person.age, s);
//修改可變字符串s
[s appendString:@"B"];
//再次輸出person.name被影響 從A變成了AB
NSLog(@"%p %p %@ %@", person.age, s, person.age, s);
如果確定給NSString賦值的對象不是NSMutableString咬腕,建議用strong
- 原因是copy過程中有一個(gè)if ([str isMemberOfClass:[str class]])判斷
當(dāng)項(xiàng)目過大時(shí),存在性能損耗
Block用copy修飾笆豁,還是strong修飾
- block創(chuàng)建時(shí)是在棧中郎汪,超出生命周期后就會(huì)被系統(tǒng)釋放掉赤赊,引發(fā)crash,用copy修飾煞赢,會(huì)拷貝一份到堆中抛计。其實(shí)用strong修飾也是可以因?yàn)槿耘f會(huì)執(zhí)行copy,算是xcode人性化的一面
block代碼塊內(nèi)self為什么用weak
- block放入堆中照筑,會(huì)被self持有吹截,在代碼塊中需要用weak聲明的self,防止循環(huán)引用