天天看點

Objective-C之property屬性分析

@property和@synthesize用來生成屬性的set和get方法

格式:

@property(屬性清單) 類型 屬性名

@synthesize 屬性名

屬性清單包括:strong(retain), copy, weak(assign), atomic, nonatomic, readonly, readwrite, getter=name, setter=name

strong和weak是引入ARC時加入的關鍵字

屬性清單與關鍵字的對應關系

屬性值 關鍵字 所有權
strong, copy, retain __strong
weak __weak
assign, unsafe_unretained __unsafe_unretained

屬性預設為assign(如果屬性是NSObject(或者它子類的)的對象時,預設為strong), readwrite, atomic

@property int i;等價于@property(assign, readwrite, atomic) int i;

@property NSString *s;等價于@property(strong, readwrite, atomic) NSString *s;

strong和retain類似,對所指的對象引用計數加1(如果所指對象是可變對象的話)

NSMutableString *str = [[NSMutableString alloc] initWithUTF8String:"mutablestring"];
member.strong = str; // 頭檔案定義@property(strong) NSString *strong; strong和str指向同一個記憶體位址
NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(str))); // 輸出2(NSLog可能對引用計數結果有影響,是以在這之前不要使用類似NSLog(@"%@", member.strong);語句,最好在檢視引用計數時先屏蔽掉其他NSLog)
NSLog(@"%@", member.strong); // 輸出mutablestring
[str deleteCharactersInRange:NSMakeRange(0, 7)];
NSLog(@"%@", member.strong); // 輸出string
           

我改變的是str的内容,但是strong卻被同時改變了,這是因為strong和str指向的是同一塊記憶體(可以在Xcode中調試View Memory of "*_strong"和View Memory of "*str"可以看到它們的Address是一緻的),該記憶體的引用計數為2,是以改變s的内容實際上就改變了strong的内容

另外如果用一個strong指針來指向不可變對象str,那麼str的引用計數不會加1

NSString *str = @"string"; // @"string"存放在記憶體的常量區(不可變),生命周期為整個程式的生命周期,引用計數為一個很大的數,不會被改變
NSString *__strong s = str; // 試圖使str的引用計數加1
NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(str))); // 引用計數不變
           

那麼如果我們不想讓strong和str指向一個地方,這時copy就派上用場了,copy和strong類似,但是它不影響所指向的對象的引用計數,如果str指向的對象是可變的,那麼copy會建立一個所指向對象的不可變副本(你不能修改copy指向的位址的内容,即使這個copy是NSMultableString,[str copy]同理),它們不指向同一個記憶體位址

NSMutableString *str = [[NSMutableString alloc] initWithUTF8String:"mutablestring"]; // 堆中配置設定記憶體
member.cp = str; // 頭檔案定義@property(copy) NSString *cp; cp指向str的副本,cp和str指向不同位址
NSLog(@"%@", member.cp); // 輸出mutablestring
[str deleteCharactersInRange:NSMakeRange(0, 7)];
NSLog(@"%@", member.cp); // 然并卵,cp沒有改變,輸出mutablestring
NSLog(@"%p %p", str, member.cp); // 位址不同

member.mscp = str; // 頭檔案定義@property(copy) NSMutableString *mscp
NSLog(@"%p %p", str, member.mscp); // 位址不同
[member.mscp deleteCharactersInRange:NSMakeRange(0, 7)]; // mscp指向不可變的副本,即使它是NSMutableString,也不能修改其指向的内容。運作時報錯Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with deleteCharactersInRange:'
           

如果str指向的對象不可變,結果又會不一樣

NSString *str = [[NSString alloc] initWithFormat:@"string"]; // str雖然在堆中配置設定記憶體,但是@"string"實際上是不能被改變的,這個對象會被添加到自動釋放池
member.cp = str;
NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(str))); // 引用計數為一個很大值
NSLog(@"%p %p", str, member.cp); // cp并沒有配置設定新的空間,因為str指向的記憶體位址不可改變(也就是說@"string"這個值無法改變,不能變成@"abc"之類的),是以cp和str指向了同一個位址
           
NSString *str = @"string"; // @"string"存放在記憶體的常量區(不可變),生命周期為整個程式的生命周期,引用計數為一個很大的數,不會被改變
member.cp = str;
NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(str))); // 一個非常大的引用計數
NSLog(@"%p %p", str, member.cp); // cp并沒有配置設定新的空間,因為str指向的記憶體位址不可改變(也就是說@"string"這個值無法改變,不能變成@"abc"之類的),是以cp和str指向了同一個位址
           

weak和assign不會對所指的對象引用計數加1(還是指向的同一個記憶體位址),它們的差別就是當weak指向的記憶體區域被釋放時,weak指針會被指派為nil,而如果用的是assign,不會被指派為nil,再去使用這個指針時,運作時會報錯

NSString *str= [[NSString alloc] initWithFormat:@"%s", "Name:zyu"];
member.weak = str; // 頭檔案定義@property(weak) NSString *weak; weak和str指向同一個記憶體位址
str= nil; // str空間釋放時,weak被指派成nil
NSLog(@"%@", member.weak); // 輸出(null)
           

等價于

NSString *str = [[NSString alloc] initWithFormat:@"%s", "Name:zyu"];
NSString * __weak _weak = str; // 還可以用關鍵字來定義weak屬性
str = nil;
NSLog(@"%@", _weak); // 輸出(null)
           

@當我把"Name:zyu"改成"zyu"時,NSLog輸出的結果不是(null),不知道是不是Xcode的bug。( ̄▽ ̄)

NSString *str= [[NSString alloc] initWithFormat:@"%s", "Name:zyu"];
member.assign= str; // 頭檔案定義@property(assign) NSString *assign; assign和str指向同一個記憶體位址
str= nil; // str空間釋放時,assign不會被指派成nil
NSLog(@"%@", member.assign); // 運作時報錯EXC_BAD_ACCESS,有時候又不報錯,沒有任何輸出(╯°□°)╯︵ ┻━┻
           

Objective-C中的@property: http://www.devtalking.com/articles/you-should-to-know-property/

Transitioning to ARC Release Notes: https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

Objective-c的@property 詳解: http://www.cnblogs.com/andyque/archive/2011/08/03/2125728.html

如何正确使用property裡面的strong,weak等關健字: http://www.devm.cn/2015/07/16/the-proper-use-of-property-keywords.html

複制對象(一)copy和mutableCopy方法: http://blog.csdn.net/jymn_chen/article/details/18887841