Objective-C之property屬性分析
阿新 • • 發佈:2019-01-30
@property和@synthesize用來生成屬性的set和get方法
格式:
@property(屬性列表) 型別 屬性名
@synthesize 屬性名
屬性列表包括:strong(retain), copy, weak(assign), atomic, nonatomic, readonly, readwrite, getter=name, setter=name
strong和weak是引入ARC時加入的關鍵字
屬性列表與關鍵字的對應關係
屬性預設為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(如果所指物件是可變物件的話)
weak和assign不會對所指的物件引用計數加1(還是指向的同一個記憶體地址),它們的區別就是當weak指向的記憶體區域被釋放時,weak指標會被賦值為nil,而如果用的是assign,不會被賦值為nil,再去使用這個指標時,執行時會報錯
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(屬性列表) 型別 屬性名
@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 |
無 |
@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