iOS 屬性修飾符copy,weak贩猎,strong熊户,assign,retain

一. 成員變量,實(shí)例變量,屬性變量

  1. 成員變量 : 用在類的內(nèi)部,無(wú)須與外部接觸.成員變量默認(rèn)是被保護(hù)的,所以不會(huì)有setter和getter方法. 成員變量是定義在{}中的變量.

  2. 實(shí)例變量: 如果變量類型是一個(gè)類. 如: UILabel * label;那么這個(gè)變量就是實(shí)例化變量. 所以實(shí)例化變量也是成員變量的一種. 不需要與外部接觸.或者稱為類的私有變量.

  3. 屬性量.@property (nonatomic, copy) NSString *age;
    屬性變量聲明之后,編譯器會(huì)自動(dòng)生成一個(gè)以下劃線開頭的實(shí)例變量_age. 不需要自己手動(dòng)再去寫實(shí)例變量. 也會(huì)自動(dòng)生成對(duì)應(yīng)的setter和getter.

二. 屬性變量的getter和setter方法

  1. setter: 給外部提供一個(gè)修改內(nèi)部屬性的接口,通過(guò)給對(duì)象指針發(fā)送該消息(調(diào)用setter方法)可以做到修改內(nèi)部的屬性值.
  2. getter: 為外部提供的一個(gè)查看內(nèi)部變量的接口.
  3. 舉例說(shuō)明.
   UILabel * label = [[UILabel alloc] init];
   [label setText:@"這是一個(gè)label"];  // 外部調(diào)用UILabel內(nèi)>部的text屬性的setter方法,修改屬性值.
   NSString * textStr = [label text];// 外部訪問(wèn)UILabel的getter方法,讀取該屬性的值.
  NSLog(@"textStr = %@",textStr);
   

   //setter方法
  - (void)setAge:(NSString *)age {
       _age = age;
 }
  //getter方法
   - (NSString *)age {
       return _age;
   }
  
   // 點(diǎn)調(diào)用
   label.text = @"這是一個(gè)label";  // '.'調(diào)用在'='左邊相當(dāng)于setter
   textStr = label.text;          // '.'調(diào)用在'='右邊相當(dāng)于getter
  1. 實(shí)戰(zhàn)
    (1). setter: 可以添加一個(gè)規(guī)則來(lái)保證set的值是否正確等用法.
// 重寫set方法,并保證該屬性的值為 >= 1
- (void)setCount:(int)count {
   if (count < 1) {
       count = 1;
   }
   _count = count;
}

(2). getter : 可以精簡(jiǎn)代碼等其他好處.
聲明一個(gè)UIColor的對(duì)象屬性.每當(dāng)該類中的一個(gè)label的背景顏色改變之后,就 賦值給這個(gè)對(duì)象.那么每次都要讀取這個(gè)label的顏色屬性. 但是如果用getter方法就可以簡(jiǎn)化為

- (UIColor *)color {
   return label.backgroundColor;
}

二. 原子性修飾符 atomic / nonatomic

  1. atomic : 原子性. 為setter方法加鎖.線程安全,但需要消耗大量的資源. 屬性默認(rèn)為原子性atomic.
  2. nonatomic : 非原子性. 不為setter方法加鎖.線程不安全.適合.資源占用低.
  3. 在多線程中原子操作是必須的.之所以這么做就是為了保證在寫未完成的時(shí)候被另一個(gè)線程讀取.造成數(shù)據(jù)錯(cuò)誤.經(jīng)典案例: 火車票的預(yù)定和購(gòu)買. 加入atomic屬性修飾之后,setter方法就會(huì)加鎖.
{lock}
   if (property != newValue) {
        [property release];
        property = [newValue retain];
    }
{unlock}
  1. nonatomic直接訪問(wèn)內(nèi)存的地址,不關(guān)心其他線程是否改變整個(gè)值,并且沒(méi)有死鎖現(xiàn)保護(hù).只需要從內(nèi)存中訪問(wèn)到當(dāng)前內(nèi)存地址中能用到的數(shù)據(jù)即可.
  2. 不要誤以為多線程加了atomic就是安全的. atomic只有在setter和getter的時(shí)候是原子操作.其他方面就不是atomic能管理的了. 想要安全就需要其他線程安全的操作了,比如加鎖.

三. 讀寫型修飾符

  1. readonly: 表明這個(gè)屬性只能讀,不能寫.系統(tǒng)只為我們生成一個(gè)getter方法下劃線開頭的成員變量.不會(huì)創(chuàng)建setter方法.
    當(dāng)希望外界能讀取我們這個(gè)屬性融欧,但是不希望被外界改變的時(shí)候就用readonly敏弃。
  2. readwrite: 表明這個(gè)屬性是可讀可寫的. 系統(tǒng)為我們這個(gè)屬性生成了setter和getter方法.
  3. 系統(tǒng)默認(rèn)為readwrite.
  4. 一般我們封裝的方法只允許外界read不允許寫. 在.h文件里用readonly修飾,在.m文件里面用readwrite修飾噪馏。這樣就可以外部只讀,內(nèi)部讀寫.
// .h文件
#import <UIKit/UIKit.h>

@interface SecondViewController : UIViewController

@property (nonatomic, strong, readonly) NSString * str;

@end
// .m文件
#import "SecondViewController.h"

@interface SecondViewController ()

@property (nonatomic, strong, readwrite) NSString * str;

@end

四. 預(yù)備知識(shí)

內(nèi)存的棧區(qū) : 由編譯器自動(dòng)分配釋放, 存放函數(shù)的參數(shù)值, 局部變量的值等.

內(nèi)存的堆區(qū) : 一般由程序員分配釋放, 若程序員不釋放, 程序結(jié)束時(shí)可能由OS回收.

五. copy

  1. copy 和 mutableCopy
    如果想要?jiǎng)?chuàng)建一個(gè)對(duì)象,該對(duì)象與源的內(nèi)容一致,那么可以用拷貝(copy或mutableCopy).
    copy拷貝出來(lái)的對(duì)象類型總是不可變類型(例如, NSString, NSDictionary, NSArray等等)
    mutableCopy拷貝出來(lái)的對(duì)象類型總是可變類型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)
NSString *string = @"Jerry";
[string copy] --> 拷貝出內(nèi)容為Jerry的NSString類型的字符串
[string mutableCopy] --> 拷貝出內(nèi)容為Jerry的>NSMutableString類型的字符串

NSDictionary *dict = @{@"name" : @"Jerry"};
[dict copy] --> 拷貝出內(nèi)容與dict相同的NSDictionary類型的字典
[dict mutableCopy] --> 拷貝出內(nèi)容與dict相同的>NSMutableDictionary類型的字典

NSArray *array = @[@"Jerry"];
[array copy] --> 拷貝出內(nèi)容與array相同的NSArray類型的數(shù)組
[array mutableCopy] --> 拷貝出內(nèi)容與array相同的>NSMutableArray類型的數(shù)組
copy和mutableCopy
  1. block為什么用copy.
    block是一個(gè)對(duì)象,所以block在創(chuàng)建的時(shí)候內(nèi)存是默認(rèn)在stack(棧)上的. 而不是在heap(堆)上的.所以他的作用域僅限創(chuàng)建時(shí)候的當(dāng)前上下文(函數(shù),方法等),當(dāng)在作用域外調(diào)用block就會(huì)崩潰. Copy可以將block從內(nèi)存棧區(qū)移動(dòng)到堆區(qū).這樣在作用域外也不會(huì)崩潰了. 但在ARC下, 使用copy與strong其實(shí)都一樣, 因?yàn)閎lock的retain就是用copy來(lái)實(shí)現(xiàn)的.block還是建議使用copy修飾.因?yàn)镸RC下就是就是用copy修飾的.
  2. copy相對(duì)于直接賦值的好處.
    先來(lái)看這個(gè)兩個(gè)的區(qū)別.
   NSArray * array;
   NSMutableArray * arrayM = [NSMutableArray array];
   [arrayM addObject:@"A"];
   array = arrayM;
   [arrayM addObject:@"B"];
   
   NSLog(@"array = %@, arrayM = %@",array,arrayM);

  // 結(jié)果
 array = (
   "A",
   "B"
 ), arrayM = (
   "A",
   "B"
 )

明明可變數(shù)組添加對(duì)象是在賦值之后, 為什么后面添加對(duì)象還會(huì)影響到不可變數(shù)組呢?
因?yàn)镺bjective-C支持多態(tài).所以表面上array是NSArray對(duì)象,但是其骨子里還是NSMutableArray對(duì)象.
這樣的話將會(huì)對(duì)后期DEBUG增加很大的成本, 可能會(huì)導(dǎo)致莫名其妙的錯(cuò)誤.

   NSArray * array;
   NSMutableArray * arrayM = [NSMutableArray array];
   [arrayM addObject:@"A"];
   array = [arrayM copy];     // 此處有不同
   [arrayM addObject:@"B"];
   
   NSLog(@"array = %@, arrayM = %@",array,arrayM);
   
// 結(jié)果
array = (
   "A"
), arrayM = (
   "A",
   "B"
)

這樣就能保證不管賦值的是可變還是不可變數(shù)組, NSArray就是NSArray了!

所以@property中NSString,NSArray,NSDictionary屬性用copy而不是strong了.

如果能夠在你的工程中正確使用copy, 將會(huì)對(duì)你的程序有不小的幫助.細(xì)節(jié)決定成敗.

  1. 深拷貝和淺拷貝
    深拷貝(內(nèi)容拷貝): 直接拷貝整個(gè)對(duì)象內(nèi)容到另一塊內(nèi)存中.
    淺拷貝(指針拷貝): 并不拷貝對(duì)象本身麦到,僅僅是拷貝指向?qū)ο蟮闹羔?指向該內(nèi)存地址.拷貝出來(lái)的對(duì)象與源對(duì)象的地址一致!這意味著修改拷貝對(duì)象的值會(huì)直接影響到源對(duì)象.

如果在多層數(shù)組中,對(duì)第一層進(jìn)行內(nèi)容拷貝欠肾,其它層進(jìn)行指針拷貝瓶颠,這種情況是屬于深復(fù)制,還是淺復(fù)制刺桃?對(duì)此粹淋,蘋果官網(wǎng)文檔有這樣一句話描述:This kind of copy is only capable of producing a one-level-deep copy. If you only need a one-level-deep copy... If you need a true deep copy, such as when you have an array of arrays...

從文中可以看出,蘋果認(rèn)為這種復(fù)制不是真正的深復(fù)制瑟慈,而是將其稱為單層深復(fù)制(one-level-deep copy)桃移。因此,有人對(duì)淺復(fù)制葛碧、完全深復(fù)制借杰、單層深復(fù)制做了概念區(qū)分。當(dāng)然进泼,這些都是概念性的東西蔗衡,沒(méi)有必要糾結(jié)于此。只要知道進(jìn)行拷貝操作時(shí)乳绕,被拷貝的是指針還是內(nèi)容即可绞惦。

5. 自定義復(fù)制

先自定義一個(gè)MyPerson的類.初始化并進(jìn)行copy或者mutableCopy會(huì)出現(xiàn)如圖問(wèn)題.找不到copyWithZone或者mutableCopyWithZone方法.

自定義類的copy.png
其實(shí)當(dāng)程序調(diào)用對(duì)象的copy方法來(lái)復(fù)制自身時(shí),底層需要調(diào)用copyWithZone:方法來(lái)完成實(shí)際的復(fù)制工作洋措,copy返回實(shí)際上就是copyWithZone:方法的返回值济蝉;mutableCopy與mutableCopyWithZone:方法也是同樣的道理。
那么怎么做才能讓自定義的對(duì)象進(jìn)行copy與mutableCopy呢菠发?需要做以下事情:
1.讓類實(shí)現(xiàn)NSCopying/NSMutableCopying協(xié)議王滤。
遵守NSCoding協(xié)議.png

2.讓類實(shí)現(xiàn)copyWithZone:/mutableCopyWithZone:方法
實(shí)現(xiàn)copyWithZero.png

該段參考:
小結(jié)iOS中的copy
iOS之對(duì)象復(fù)制

六. assign

  1. assign是賦值屬性.引用計(jì)數(shù)不加1.
  2. 一般用來(lái)修飾基礎(chǔ)數(shù)據(jù)類型(NSInteger,CGFloat等)和C數(shù)據(jù)類型(int,float,double)等.
  3. assign是指針賦值,不對(duì)引用計(jì)數(shù)操作雷酪,使用之后如果沒(méi)有置為nil淑仆,可能就會(huì)產(chǎn)生野指針.指向?qū)ο蟮刂返?jì)數(shù)不+1涝婉,但當(dāng)?shù)刂芬糜?jì)數(shù)為0時(shí)哥力,assign不會(huì)對(duì)地址進(jìn)行數(shù)據(jù)的抹除操作,只是進(jìn)行值釋放。這就導(dǎo)致野指針存在吩跋,即當(dāng)這塊地址還沒(méi)寫上其他值前寞射,能輸出正常值,但一旦重新寫上數(shù)據(jù)锌钮,該指針隨時(shí)可能沒(méi)有值桥温,造成奔潰。

七. weak

  1. 引用計(jì)數(shù)不加1.
  2. 當(dāng)使用weak修飾的屬性梁丘,當(dāng)對(duì)象釋放的時(shí)候侵浸,系統(tǒng)會(huì)對(duì)屬性賦值nil,objective-c有個(gè)特性就是對(duì)nil對(duì)象發(fā)送消息也就是調(diào)用方法。weak特性要求不保留傳入的對(duì)象氛谜。如果該對(duì)象被釋放掏觉,那么相應(yīng)的實(shí)例變量會(huì)被自動(dòng)賦為nil。這么做可以避免產(chǎn)生懸空指針值漫。懸空指針指向的是不再存在的對(duì)象澳腹。向懸空指針發(fā)送消息通常會(huì)導(dǎo)致程序崩潰。相應(yīng)的存方法會(huì)將傳入的對(duì)象直接賦給實(shí)例變量杨何。
  3. weak只能修飾對(duì)象類型.
    weak只能修飾對(duì)象類型
  4. 用weak修飾代理屬性和用來(lái)解決循環(huán)強(qiáng)引用.

八.retain

  1. retain用在MRC情況下酱塔,被retain修飾的對(duì)象,引用計(jì)數(shù)retainCount要加1的危虱。
  2. retain只能修飾oc對(duì)象羊娃,不能修飾非oc對(duì)象,比如說(shuō)CoreFoundation對(duì)象就是C語(yǔ)言框架槽地,它沒(méi)有引用計(jì)數(shù)迁沫,也不能用retain進(jìn)行修飾。
  3. retain一般用來(lái)修飾非NSString 的NSObject類和其子類捌蚊。

九. strong

  1. 表示對(duì)對(duì)象的強(qiáng)引用.
  2. strong和weak默認(rèn)用strong
  3. retainCount + 1
  4. 對(duì)兩個(gè)對(duì)象之間互相強(qiáng)引用造成循環(huán)引用,內(nèi)存泄露.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末集畅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缅糟,更是在濱河造成了極大的恐慌挺智,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窗宦,死亡現(xiàn)場(chǎng)離奇詭異赦颇,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)赴涵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門媒怯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人髓窜,你說(shuō)我怎么就攤上這事扇苞∑鄣睿” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵鳖敷,是天一觀的道長(zhǎng)脖苏。 經(jīng)常有香客問(wèn)我,道長(zhǎng)定踱,這世上最難降的妖魔是什么棍潘? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮崖媚,結(jié)果婚禮上亦歉,老公的妹妹穿的比我還像新娘。我一直安慰自己畅哑,他們只是感情好鳍徽,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著敢课,像睡著了一般阶祭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上直秆,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天濒募,我揣著相機(jī)與錄音,去河邊找鬼圾结。 笑死瑰剃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的筝野。 我是一名探鬼主播晌姚,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼歇竟!你這毒婦竟也來(lái)了挥唠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤焕议,失蹤者是張志新(化名)和其女友劉穎宝磨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盅安,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唤锉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了别瞭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窿祥。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蝙寨,靈堂內(nèi)的尸體忽然破棺而出晒衩,到底是詐尸還是另有隱情号胚,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布浸遗,位于F島的核電站,受9級(jí)特大地震影響箱亿,放射性物質(zhì)發(fā)生泄漏跛锌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一届惋、第九天 我趴在偏房一處隱蔽的房頂上張望髓帽。 院中可真熱鬧,春花似錦脑豹、人聲如沸郑藏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)必盖。三九已至,卻和暖如春俱饿,著一層夾襖步出監(jiān)牢的瞬間歌粥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工拍埠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留失驶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓枣购,卻偏偏與公主長(zhǎng)得像嬉探,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子棉圈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容