OC中@property屬性關鍵字的使用(assign/weak/strong/copy)


 

OC中@property屬性關鍵字的使用(assign/weak/strong/copy) 

 

一、assign

用於 ‘基本數據類型’、‘枚舉’、‘結構體’ 等非OC對象類型

eg:int、bool等

 

二、 weak

1. 一般應用: UI控件

2. 詳細說明:

(1)為什么建議UI控件一般使用weak?首先我們從controller來看,controller是被系統用強指針引用着,所以如果 controller 還存在,里面的子控件也會存在,那么controller 強引用着它的view(從 controller 中它的 view 的屬性是 retain 看出來的,retain 就是 MRC 年代的強引用),那么 view 又強引用着它的數組對象subviews,數組對象又引用着它所包含的數組內容,所以當我們創建出來一個UI控件並將其加入到subviews的時候,它就會被一個強指針所引用着,我們可以簡化一下這個過程:--> Controller --> View --> Subviews(數組) --> 數組內容(添加到其中的UI控件)

(2)清楚了過程之后,我們來看我們所創建的對象,如果我們所創建的是一個臨時變量的話,那么當出去作用域之后對象就被銷毀,但是這里請注意,這里分為兩個內存空間,一個是對象的內存空間,一個是指針的內存空間,如果創建的是臨時變量的話,一旦出了作用域那么我們的指針內存是被清空了,但是我們的內容如果加到了subviews中,就會被subviews強引用,那么我們的控件就還會存在,只不過是一個指向它的指針被清空了而已。

(3)回過頭我們說說全局變量,全局變量的話,指針會一直存在,這里面談談為什么要用weak,其實只要我們創建的控件加入到subviews中去的話,那么這個控件就會一直存在,所以在這里我們所創建的指針是weak或strong其實只不過是多一個實線虛線的問題,也就是控件已經被強引用了,你再給它添加一個強引用或者弱引用在使用上都不會有什么問題,但是問題來了,如果我們remove了這個控件,我們subViews中的那根線被切斷,也就是這個代表我不再需要這個控件了,那么這個時候如果再用一個strong來連接它,那么對象就不會被清除,既然我們都不需要它了,為什么我還強引用它?這也就是為什么我們再這里用弱引用的原因。`簡言之,就是內存使用上的合理性,當這個控件我們需要的時候其實已經有一個強引用在引用着它,我們沒有必要再弄一根指針來強引用着它,當我們不需要它的時候,如果是weak的話自然而然直接釋放掉了,如果strong的話還會保留它,既然我們沒用了我們為什么還要留着它而占用我們寶貴的內存呢?我們也可以看一下這張圖片用來理解:

 

(4)這里特殊說一下IBOutlet中的拖線創建,我們可以發現,如果用storyboard或者xib進行的脫線創建,蘋果都會自動降屬性置為weak,這種做法似乎也符合我們之前的說法,但是蘋果又會在之前加了一個IBOutlet這個關鍵詞,那么這個詞是什么意思呢?我們看一下蘋果的官網解釋: The symbol IBOutlet is used only by Xcode, to determine when a property is an outlet; it has no actual value. 意思很清楚了,它僅僅是指定了一個屬性是一個 外部設置的,並沒有實質的含義,通常與外界連接是通過當前的 viewcontroller 。那么在引用上又有什么不同呢?在官方文檔中是這么說的,在我們創建了IBOutlet之后,我們系統會有一個自動對它進行一個強引用,也就是又多了一條實線連接着它,當控件從我們的subviews中移除之后,這條線會自動判斷去留,也就是不會對我們的內存的性能造成影響,該在的時候我在,該消失的時候自己就會消失了。這里也用一張圖來說明:

 

 

在我寫demo的時候有一點需要注意,就是當我們將控件從subViews中remove調之后,這個時候打印指針還存在,說明指針並不會馬上銷毀,而是進行下一輪消息循環之后才會發現這個指針被銷毀了.

 

3. 總結:

我們首先是從內存的利用上,我們建議對UI控件采用weak,其次是觀察蘋果的聲明方式,依然是建議使用weak,因為標准都是參考於蘋果,而且合理性也擺在那里,為什么不用呢? 

 

三、 strong

OC對象類型(NSArray、NSDate、NSNumber、模型類)

一個對象只要有強指針引用着,就不會被銷毀 

 

四、 copy

1. 一般用在NSString*類型、block類型上

2.  copy語法的作用:產生副本。 且copy返回的是不可變的副本,mutableCopy返回的是可變的副本。

3. 修改了副本並不會影響源對象,修改了源對象,並不會影響副本。

4. copy在屬性聲明中的使用,直接舉例說明

@interface ViewController ()//注意這里雖然是copy的屬性,但是我們這個指針還是強引用的

@property(nonatomic,copy)NSString*name;

@end

 

@implementation Viewcontroller

-(void)viewDidLoad

[self viewDidLoad]; 

NSMutableString*str = [NSMutableString stringWithFormat:@"aaa"]; 

self.name = str; 

[str appendString:@"bbb"]; 

NSLog(@"str= %@",str); 

NSLog(@"name = %@",self.name); 

NSLog(@"%p,%p",str, self.name);

}

@end

 

我們來看一下說出的結果:

str = aaabbb

name = aaa

輸出的內存地址:0x7f90f3028180 , 0x7f90f3027450

 

這說明了這個copy的含義就是,我們在給name屬性賦值的時候,,系統默認先將str執行一次copy方法,然后再將結果賦給我們的屬性,只有這樣你再之后對str修改之后,name的值還是不變的,說明兩個指針其實指向的是不同的內容,之后我們又打印了我們的指針值,得出不同的結果又證明了上述所說。

 

5. 注意:並不是所有情況下我們的string都必須使用copy,因為如果我們的需求是希望string是隨着我的改變而改變的,那么這個時候應該使用strong。

 

6. 類的copy:

如果我們想實現類的copy,必須實現一個方法:-(id)copyWithZome:(NSZone*)zone; 這是為什么呢?我們去 NSString 中去尋找答案,那么我們會發現其實 NSString 已經遵守了 NSCopying 與 NSMutableCopying 的協議,我們主要看 NSCopying ,進入這個協議之后你會發現 -(id)copyWithZome:(NSZone*)zone 這個方法,也就是說NSString 已經遵守了協議的這個方法,所以才能直接實現 copy 的方法。所以如果想實現自定義類的 copy 方法,我們是需要先遵守 NSCopying 協議,然后實現-(id)copyWithZome:(NSZone*)zone的方法:

-(id)copyWithZone:(NSZone *)zone

{

Mitchell*copyMit = [[Mitchell allocWithZone:zone] init];

copyMit.name = self.name;return copyMit;

}

zone:系統返回給我們 copy 對象的內存空間

注意:必須在初始化方法中給屬性賦值,才能讓 copy 出的對象和原來的對象有相同的屬性。

 

7. 再說一下 copy 類中的 set 方法,如果屬性是 copy 的,那么系統默認只會在 set 方法中調用 copy 的方法:

-(void)setName:(Mitchell*)name

_name = [name copy];

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM