標籤:
關於Objective-C 的property,很多iOS開發的新手都會很迷惑,也會包括有經驗的iOS開發程式員,
因為Objective-C的property,說多不多,說少卻也不少,從MRR(Manual Retain Release )到ARC模式,很多屬性功能類似
名稱卻不一樣,比如strony和retain,而且又牽扯到release, autorelease, alloc ,new,copy等一眾函數,
所以看著很容被繞進去,迷失在這眾多的property,
今天特地梳理支援ARC(iOS 5+) 的propterty的關鍵詞:
strong, weak, copy, readonly/readwrite, atomic/nonatomic,assign,retain
由於strong和retain功能相同,所以會在最後總結的時候,比較所有的這些關鍵詞異同點
1:定義一個property
如下,我們定義一個car 的interface, 該屬性有一個property 為 brand(品牌)
// Car.h
#import <Foundation/Foundation.h>@interface Car : NSObject@property NSString *brand;@end
// Car.m#import "Car.h"@implementation car@synthesize brand = _brand;@end
2:屬性的getter 和setter方法和synthesize
編譯器會預設的為屬性產生getter 和setter方法
- (NSString *)brand{ return _brand;//_brand即使synthesize指定的屬性名稱}- (void)setBrand:(NSString *)brand{ _brand = brand;}
注意:synthesize 不是必須明確聲明,除非手動些屬性的getter和setter方法
否則,complier預設產生的code 如下格式
@synthesize brand = _brand
synthesize關鍵字預設方式是:將brand屬性對應的執行個體便令聲明為_brand,即_ + propertyname
當然可以自己指定比如brand = xxxbrand
編譯器預設會將getter方法和屬性同名,setter方法為set+屬性(首字母大寫),例如setBrand
可以指定屬性的getter和setter方法名稱
@property (nonatomic,getter=getBrand, setter = setBrand:)NSString *brand;
3:readonly和readwrite
聲明 readonly屬性
@property (readonly,getter=getBrand)NSString *brand;
聲明了readonly的屬性,一定沒有setter方法,所以你可以使用getter或者 dot方法 擷取屬性的值,但肯定不可以使用
setter方法修改
Car *c = [[Car alloc]init];0 [c setBrand:@"tony"]; //Error NSLog(@"%@", [c getBrand]);
聲明為readonly 不意味著我們不可以修改,propery 的accessor method 本來就是提供給其他介面調用的,
在我們內部,是直接操縱_brand執行個體的, 如下
// Car.h
- (void)setBrand:(NSString *)brand;
// Car.m
- (void )setBrand:(NSString *)brand;{ _brand = brand;}
readonly 對應的readwrite 屬性, readwrite 是default的behavior,可以不顯示聲明
@property (readwrite)NSString *brand;
4:atomic, nonatomic
atomic 原子的,default behavior,支援多線程操作, 代價是開銷比nonatomic大
如果聲明一個屬性,確定不會運行在多線程的環境,可以直接聲明為nonatomic
@property (nonatomic)NSString *brand;
記憶體管理
Ojective-C 記憶體模型中,不管是MRR,還是ARC,都是根據對象的引用計數來確定對象是否回收
當對象的 引用計數為0,就會被回收(不一定是立即回收)
從引用計數的原理出發,Objective-C 提出了三種相關的是屬性
strong, weak, copy
1:strony 屬性
strong屬性,即聲明一個對象擁有另外一個對象,引用計數 + 1
加入 A對象 有個strong 屬性的執行個體對象B, 則在A對象釋放之前,B是不會釋放的
看如下sample code
聲明一個類Person,Person有一個屬性name
//// Person.h#import <Foundation/Foundation.h>@interface Person : NSObject@property (nonatomic) NSString *name;@end
// Person.m#import "Person.h"@implementation Person- (NSString *)description{ return self.name;}@end
聲明一個Car 類,有兩個屬性 model和driver
// Car.h#import <Foundation/Foundation.h>#import "Person.h"@interface Car : NSObject@property (nonatomic) NSString *model;@property (nonatomic,strong) Person *driver;@end
main.m
// main.m#import <Foundation/Foundation.h>#import "Car.h"#import "Person.h"int main(int argc, const char * argv[]) { @autoreleasepool { Person *john = [[Person alloc] init]; john.name = @"John"; Car *honda = [[Car alloc] init]; honda.model = @"Honda Civic"; honda.driver = john; NSLog(@"%@ is driving the %@", honda.driver, honda.model); } return 0;}
可以看到,hoda對象對driver對象負責
2:weak屬性
strong 屬性,很直觀的顯示對象直接的關係,但也很容易引起記憶體泄露,
看如下代碼,我們稍微小改了Person.h ,增加了Car 屬性,
// Person.h#import <Foundation/Foundation.h>@class Car;@interface Person : NSObject@property (nonatomic) NSString *name;@property (nonatomic, strong) Car *car;@end
則在main.m
增加一行
john.car = honda;
則此時,john和hoda互相持有對方
二者這件形成了 retain cycle(互相持有的迴圈),就是典型的記憶體泄露的一種情況
如果car聲明為weak,這個問題即迎刃而解
@property (nonatomic, weak) Car *car;
3:copy 屬性
copy不同於strong, 並不擁有copy的對象,而是複製該對象(必須conform NSCopying
protocol )
sample code
#import <Foundation/Foundation.h>#import "Car.h"#import "Person.h"int main(int argc, char *argv[]){ Car *bmw = [[Car alloc]init]; Person *driver = [[Person alloc]init]; NSMutableString *name = [NSMutableString stringWithFormat:@"zhangsan"];//mutable 的name 為zhangsan [driver setName:name]; [name setString:@"lisi"];//修改為lisi [driver setCar:bmw]; [bmw setModel:@"X5"]; [bmw setDriver:driver]; NSLog(@"%@", [driver name]);//仍然是zhangsan}
copy 屬性在被賦值的時候就copy了該值,所以即使該值是mutable的,屬性的值也不會被修改,
現對於strong的持有對象,copy特別適合只是簡單儲存值得屬性
以上都是ARC支援的屬性。
4:屬性retain
等同於 strong
5:unsafe_unretained
類似於weak,和weak不同的是,如果weak 屬性指向的對象如果被銷毀後,weak 屬性被置為nil,
而 unsafe_unretained 不會,則又可能形成懸垂指標的問題
6:assign
預設的屬性,不需要顯示聲明
指定setter方法進行簡單的賦值 ,對基礎資料類型(NSInteger,CGFloat)
和C資料類型(int, float, double, char)等等。
總結:
atomic //default
nonatomic
strong=retain //default
weak
assign //default
unsafe_unretained
copy
readonly
readwrite //default
引用:
http://rypress.com/tutorials/objective-c/properties
http://rypress.com/tutorials/objective-c/memory-management
http://stackoverflow.com/questions/8927727/objective-c-arc-strong-vs-retain-and-weak-vs-assign
Objective-C Properties 詳解