一. 成員變量,實例變量,屬性變量
成員變量 : 用在類的內(nèi)部,無須與外部接觸.成員變量默認(rèn)是被保護的,所以不會有setter和getter方法. 成員變量是定義在{}中的變量.
實例變量: 如果變量類型是一個類. 如: UILabel * label;那么這個變量就是實例化變量. 所以實例化變量也是成員變量的一種. 不需要與外部接觸.或者稱為類的私有變量.
屬性量.
@property (nonatomic, copy) NSString *age;
屬性變量聲明之后,編譯器會自動生成一個以下劃線開頭的實例變量_age. 不需要自己手動再去寫實例變量. 也會自動生成對應(yīng)的setter和getter.
二. 屬性變量的getter和setter方法
- setter: 給外部提供一個修改內(nèi)部屬性的接口,通過給對象指針發(fā)送該消息(調(diào)用setter方法)可以做到修改內(nèi)部的屬性值.
- getter: 為外部提供的一個查看內(nèi)部變量的接口.
- 舉例說明.
UILabel * label = [[UILabel alloc] init]; [label setText:@"這是一個label"]; // 外部調(diào)用UILabel內(nèi)>部的text屬性的setter方法,修改屬性值. NSString * textStr = [label text];// 外部訪問UILabel的getter方法,讀取該屬性的值. NSLog(@"textStr = %@",textStr); //setter方法 - (void)setAge:(NSString *)age { _age = age; } //getter方法 - (NSString *)age { return _age; } // 點調(diào)用 label.text = @"這是一個label"; // '.'調(diào)用在'='左邊相當(dāng)于setter textStr = label.text; // '.'調(diào)用在'='右邊相當(dāng)于getter
- 實戰(zhàn)
(1). setter: 可以添加一個規(guī)則來保證set的值是否正確等用法.// 重寫set方法,并保證該屬性的值為 >= 1 - (void)setCount:(int)count { if (count < 1) { count = 1; } _count = count; }(2). getter : 可以精簡代碼等其他好處.
聲明一個UIColor的對象屬性.每當(dāng)該類中的一個label的背景顏色改變之后,就 賦值給這個對象.那么每次都要讀取這個label的顏色屬性. 但是如果用getter方法就可以簡化為- (UIColor *)color { return label.backgroundColor; }
二. 原子性修飾符 atomic / nonatomic
- atomic : 原子性. 為setter方法加鎖.線程安全,但需要消耗大量的資源. 屬性默認(rèn)為原子性atomic.
- nonatomic : 非原子性. 不為setter方法加鎖.線程不安全.適合.資源占用低.
- 在多線程中原子操作是必須的.之所以這么做就是為了保證在寫未完成的時候被另一個線程讀取.造成數(shù)據(jù)錯誤.經(jīng)典案例: 火車票的預(yù)定和購買. 加入atomic屬性修飾之后,setter方法就會加鎖.
{lock} if (property != newValue) { [property release]; property = [newValue retain]; } {unlock}
- nonatomic直接訪問內(nèi)存的地址,不關(guān)心其他線程是否改變整個值,并且沒有死鎖現(xiàn)保護.只需要從內(nèi)存中訪問到當(dāng)前內(nèi)存地址中能用到的數(shù)據(jù)即可.
- 不要誤以為多線程加了atomic就是安全的. atomic只有在setter和getter的時候是原子操作.其他方面就不是atomic能管理的了. 想要安全就需要其他線程安全的操作了,比如加鎖.
三. 讀寫型修飾符
- readonly: 表明這個屬性只能讀,不能寫.系統(tǒng)只為我們生成一個getter方法下劃線開頭的成員變量.不會創(chuàng)建setter方法.
當(dāng)希望外界能讀取我們這個屬性,但是不希望被外界改變的時候就用readonly。- readwrite: 表明這個屬性是可讀可寫的. 系統(tǒng)為我們這個屬性生成了setter和getter方法.
- 系統(tǒng)默認(rèn)為readwrite.
- 一般我們封裝的方法只允許外界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ù)備知識
內(nèi)存的棧區(qū) : 由編譯器自動分配釋放, 存放函數(shù)的參數(shù)值, 局部變量的值等.
內(nèi)存的堆區(qū) : 一般由程序員分配釋放, 若程序員不釋放, 程序結(jié)束時可能由OS回收.
五. copy
- copy 和 mutableCopy
如果想要創(chuàng)建一個對象,該對象與源的內(nèi)容一致,那么可以用拷貝(copy或mutableCopy).
copy拷貝出來的對象類型總是不可變類型(例如, NSString, NSDictionary, NSArray等等)
mutableCopy拷貝出來的對象類型總是可變類型(例如, 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
- block為什么用copy.
block是一個對象,所以block在創(chuàng)建的時候內(nèi)存是默認(rèn)在stack(棧)上的. 而不是在heap(堆)上的.所以他的作用域僅限創(chuàng)建時候的當(dāng)前上下文(函數(shù),方法等),當(dāng)在作用域外調(diào)用block就會崩潰. Copy可以將block從內(nèi)存棧區(qū)移動到堆區(qū).這樣在作用域外也不會崩潰了. 但在ARC下, 使用copy與strong其實都一樣, 因為block的retain就是用copy來實現(xiàn)的.block還是建議使用copy修飾.因為MRC下就是就是用copy修飾的.- copy相對于直接賦值的好處.
先來看這個兩個的區(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ù)組添加對象是在賦值之后, 為什么后面添加對象還會影響到不可變數(shù)組呢?
因為Objective-C支持多態(tài).所以表面上array是NSArray對象,但是其骨子里還是NSMutableArray對象.
這樣的話將會對后期DEBUG增加很大的成本, 可能會導(dǎo)致莫名其妙的錯誤.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, 將會對你的程序有不小的幫助.細(xì)節(jié)決定成敗.
- 深拷貝和淺拷貝
深拷貝(內(nèi)容拷貝): 直接拷貝整個對象內(nèi)容到另一塊內(nèi)存中.
淺拷貝(指針拷貝): 并不拷貝對象本身,僅僅是拷貝指向?qū)ο蟮闹羔?指向該內(nèi)存地址.拷貝出來的對象與源對象的地址一致!這意味著修改拷貝對象的值會直接影響到源對象.如果在多層數(shù)組中,對第一層進行內(nèi)容拷貝,其它層進行指針拷貝,這種情況是屬于深復(fù)制,還是淺復(fù)制?對此,蘋果官網(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)。因此,有人對淺復(fù)制、完全深復(fù)制、單層深復(fù)制做了概念區(qū)分。當(dāng)然,這些都是概念性的東西,沒有必要糾結(jié)于此。只要知道進行拷貝操作時,被拷貝的是指針還是內(nèi)容即可。
5. 自定義復(fù)制
先自定義一個MyPerson的類.初始化并進行copy或者mutableCopy會出現(xiàn)如圖問題.找不到copyWithZone或者mutableCopyWithZone方法.
其實當(dāng)程序調(diào)用對象的copy方法來復(fù)制自身時,底層需要調(diào)用copyWithZone:方法來完成實際的復(fù)制工作,copy返回實際上就是copyWithZone:方法的返回值;mutableCopy與mutableCopyWithZone:方法也是同樣的道理。自定義類的copy.png
那么怎么做才能讓自定義的對象進行copy與mutableCopy呢?需要做以下事情:
1.讓類實現(xiàn)NSCopying/NSMutableCopying協(xié)議。遵守NSCoding協(xié)議.png
2.讓類實現(xiàn)copyWithZone:/mutableCopyWithZone:方法實現(xiàn)copyWithZero.png
該段參考:
小結(jié)iOS中的copy
iOS之對象復(fù)制
六. assign
- assign是賦值屬性.引用計數(shù)不加1.
- 一般用來修飾基礎(chǔ)數(shù)據(jù)類型(NSInteger,CGFloat等)和C數(shù)據(jù)類型(int,float,double)等.
- assign是指針賦值,不對引用計數(shù)操作,使用之后如果沒有置為nil,可能就會產(chǎn)生野指針.指向?qū)ο蟮刂返嫈?shù)不+1,但當(dāng)?shù)刂芬糜嫈?shù)為0時,assign不會對地址進行數(shù)據(jù)的抹除操作,只是進行值釋放。這就導(dǎo)致野指針存在,即當(dāng)這塊地址還沒寫上其他值前,能輸出正常值,但一旦重新寫上數(shù)據(jù),該指針隨時可能沒有值,造成奔潰。
七. weak
- 引用計數(shù)不加1.
- 當(dāng)使用weak修飾的屬性,當(dāng)對象釋放的時候,系統(tǒng)會對屬性賦值nil,objective-c有個特性就是對nil對象發(fā)送消息也就是調(diào)用方法。weak特性要求不保留傳入的對象。如果該對象被釋放,那么相應(yīng)的實例變量會被自動賦為nil。這么做可以避免產(chǎn)生懸空指針。懸空指針指向的是不再存在的對象。向懸空指針發(fā)送消息通常會導(dǎo)致程序崩潰。相應(yīng)的存方法會將傳入的對象直接賦給實例變量。
- weak只能修飾對象類型.
weak只能修飾對象類型- 用weak修飾代理屬性和用來解決循環(huán)強引用.
八.retain
- retain用在MRC情況下,被retain修飾的對象,引用計數(shù)retainCount要加1的。
- retain只能修飾oc對象,不能修飾非oc對象,比如說CoreFoundation對象就是C語言框架,它沒有引用計數(shù),也不能用retain進行修飾。
- retain一般用來修飾非NSString 的NSObject類和其子類。
九. strong
- 表示對對象的強引用.
- strong和weak默認(rèn)用strong
- retainCount + 1
- 對兩個對象之間互相強引用造成循環(huán)引用,內(nèi)存泄露.




