讀寫屬性:readwrite
、readonly
setter語意:assign
、retain
/ copy
原子性(多線程管理):atomic
、 nonatomic
強弱引用:strong
、 weak
html
讀寫屬性:
readwrite
:同時生成 set
和 get
方法(默認)
readonly
:只會生成 get
方法ios
控制set方法的內存管理:
retain
:release
舊值,retain
新值。但願得到源對象的全部權時,對其餘 NSObject
和其子類(用於 OC
對象)
copy
:release
舊值,copy
新值。但願得到源對象的副本而不改變源對象內容時(通常用於 NSString
,block
)
assign
:直接賦值,不作任何內存管理(默認屬性),控制需不需生成 set
方法。對基礎數據類型 (NSInteger
,CGFloat
)和C數據類型(int
, float
, double
, char
, 等等),另外還有id類型segmentfault
原子性(多線程管理):數組
atomic
nonatomic
@synchronized
(變量)來對該變量進行加鎖(加鎖的目的經常是爲了同步或保證原子操做)。強指針(strong)、弱指針(weak)安全
strong
strong
系統通常不會自動釋放,在 oc
中,對象默認爲強指針。做用域銷燬時銷燬引用。在實際開放中通常屬性對象通常 strong
來修飾(NSArray
,NSDictionary
),在使用懶加載定義控件的時候,通常也用strong。weak
weak
所引用對象的計數器不會加一,當對象被釋放時指針會被自動賦值爲 nil
,系統會馬上釋放對象。__unsafe_unretained
弱引用 當對象被釋放時指針不會被自動賦值爲 ni
assign
的(至關於 __unsafe_unretained
)retain
的 (至關於 __strong
)sb
或者 xib
給控件拖線的時候,爲何拖出來的先屬性都是用 weak 修飾呢?xib
或者 sb
裏面添加控件的時候,添加的子視圖是添加到了跟視圖 View
上面,而 控制器 Controller
對其根視圖 View
默認是強引用的,當咱們的子控件添加到 view
上面的時候,self.view addSubView:
這個方法會對添加的控件進行強引用,若是在用 strong
對添加的子控件進行修飾的話,至關於有兩條強指針對子控件進行強引用, 爲了不這種狀況,因此用 weak
修飾。ARC管理內存是用 assign
仍是用 weak
?
assign
: 若是因爲某些緣由代理對象被釋放了,代理指針就變成了野指針。
weak
: 若是因爲某些緣由代理對象被釋放了,代理指針就變成了空指針,更安全(weak
不能修飾基本數據類型,只能修飾對象)。bash
weak的做用:
weak
關鍵字的做用弱引用,所引用對象的計數器不會加一,並在引用對象被釋放的時候自動被設置爲 nil
,大大避免了野指針訪問壞內存引發崩潰的狀況,另外 weak
還能夠用於解決循環引用。服務器
使用場景:
用於一些對象相互引用的時候,避免出現強強引用,對象不能被釋放,出現內存泄露的問題。多線程
實現原理:
runtime
維護了一個 weak
表,用於存儲指向某個對象的全部 weak
指針。weak
表實際上是一個hash(哈希)表,Key
是所指對象的地址,Value
是 weak
指針的地址(這個地址的值是所指對象的地址)數組。(備註:strong
是經過 runtime
維護的一個自動計數表結構)
weak 的實現原理可歸納三步:併發
runtime
會調用 objc_initWeak
函數,初始化一個新的 weak
指針指向對象的地址。objc_initWeak
函數會調用 objc_storeWeak()
函數, objc_storeWeak()
的做用是更新指針指向,建立對應的弱引用表。clearDeallocating
函數。clearDeallocating
函數首先根據對象地址獲取全部 weak
指針地址的數組,而後遍歷這個數組把其中的數據設爲 nil
,最後把這個 entry
從 weak
表中刪除,最後清理對象的記錄。文章推薦:
iOS 底層解析weak的實現原理(包含weak對象的初始化,引用,釋放的分析)
淺談iOS之weak底層實現原理app
retain
操做// 深複製:產生了新對象,新對象(副本對象)的計數器是1, 源對象的計數器不變
// str : 1
NSString *str = [NSString stringWithFormat:@"Tom"];
// str2 : 1
NSMutableString *str2 = [str mutableCopy];
NSLog(@"str=%zd, str2=%zd", [str retainCount], [str2 retainCount]);
[str2 release];
複製代碼
// 淺複製:沒有產出新對象, 源對象(副本對象)的計數器會+1
NSString *str = [NSString stringWithFormat:@"Jack"];
NSString *str2 = [str copy];
[str2 release];
NSLog(@"%zd", [str retainCount]);
複製代碼
copy
產生不可變副本,mutableCopy
產生可變副本
copy
和
mutableCopy
),只是Foundation庫中的類的對象能夠直接複製,自定義的類的對象須要作一些額外的工做才能複製,但實際作app幾乎不須要複製自定義類的對象。
copy
、mutableCopy
對比不可變對象 copy
成 不可變對象 是淺複製,其餘都是深複製。(不可變對象指NSArray、NSDictionary、NSString等)
NSMutableArray
被 copy
、strong
修飾後的變化 把NSMutableArray用copy修飾有時就會crash,由於對這個數組進行了增刪改操做,而copy後的數組變成了不可變數組NSArray,沒有響應的增刪改方法,因此對其進行增刪改操做就會報錯。 舉例以下:
NSMutableArray *b = [NSMutableArray array];
a = b;
複製代碼
@property (nonatomic, copy) NSMutableArray *a;
NSMutableArray *b = [NSMutableArray array];
// a被copy後就成了NSArray了。
a = [b copy];
複製代碼
@property (nonatomic, strong) NSMutableArray *a;
若是是 strong
,直接是賦值 a = b
;右邊是什麼,左邊就是什麼,而且是強引用新值,左邊的類型會與右邊的相同,不會改變。iOS 深拷貝淺拷貝與@property 引用計數關鍵字Strong,Copy,Weak,Assign
iOS 淺談:深.淺拷貝與copy.strong
數組的屬性修飾符到底用strong仍是copy?
iOS中copy和mutableCopy的詳細分析
咱們經過實際操做來講明,咱們把str賦值給 zhangsan
的 name
屬性,而後去改變 str
,結果: 用 @property (nonatomic, retain) NSString *name;
修飾的name答應結果爲 zhangsanabc
,name
屬性被修改了; 用 @property (nonatomic, copy) NSString *name;
修飾的 name
答應結果爲 zhangsan
,name
屬性沒有被修改。
NSMutableString *str = [NSMutableString string];
str.string = @"zhangsan";
Person *zhangsan = [[[Person alloc] init] autorelease];
zhangsan.name = str;
[str appendString:@"abc"];
NSLog(@"%@ %@", str, zhangsan.name);
複製代碼
下面咱們來看代碼set方法的內部實現: 當.h用@property (nonatomic, retain) NSString *name;
時,_name = [name retain];
至關於[name retain]
和 _name = name;
,而這兩句話至關因而先把原來的做引用計數+1,再把指針付給 _name
,實際上指向的是一塊內存,這樣會致使原來的內容改變,_name
也會改變,而實際中咱們通常不但願 _name
改變,因此咱們不用retain。
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release];
_name = [name retain];
//_name = [name retain];至關於下邊兩句,而這兩句話至關因而先把原來的做引用計數+1,再把指針付給_name,實際上指向的是一塊內存,這樣會致使原來的內容改變,_name也會改變,而實際中咱們通常不但願_name改變,因此咱們不用retain
// [name retain];
// _name = name;
}
}
- (void)dealloc {
// [_name release];
// _name = nil;
self.name = nil;
[super dealloc];
}
複製代碼
當.h用@property (nonatomic, copy) NSString *name;
時,當傳入的值爲可變對象時,調用_name = [name copy];
copy
會建立一個新的對象賦值給 _name
,因此 _name
和 name
是兩塊無關的內容,改變 name
不會影響 _name
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release];
// 當傳入的值爲可變對象時,copy會建立一個新的對象賦值給_name,因此_name和name是兩塊無關的內容,改變name不會影響_name
_name = [name copy];
}
}
- (void)dealloc {
// [_name release];
// _name = nil;
self.name = nil;
[super dealloc];
}
複製代碼
@synthesize propertyName
,編譯器先會查找這個屬性名的setter方法和getter方法有沒有被人爲實現,若是已經實現,則再也不實現,若是沒有,則會幫咱們生成一個屬性命的setter方法和getter方法。@synthesize propertyName
,編譯器還會作一件事情,在類成員變量中查找一個名爲 _propertyName
的成員變量,若是沒有,再繼續查找名爲 propertyName
的成員變量,若是這兩個都沒有,編譯器會自動爲咱們生成一個私有的名爲 _propertyName
的成員變量。注意,系統自動建立的都是私有的。@synthesize propertyName = varName
;時,setter
和 getter
方法所對應的是一個名爲 varName
的成員變量,修改和讀取的是 varName
成員變量的值。@synthesize propertyName
時,在Xcode 4.5以前的版本不會幫咱們自動實現 setter
和 getter
方法,系統固然也再也不會爲咱們生成對應的成員變量。可是在Xcode 4.5以後能夠不用寫@synthesize了,就跟三、4同樣了。@synthesize
,又在實現文件中人爲重寫 setter
和 getter
方法時,那麼 @synthesize
將再也不工做,也就不會爲咱們建立沒有定義的 _propertyName
成員變量了,這時候若是在 setter
和 getter
方法中調用 _propertyName
將會發生編譯錯誤