實(shí)例變量
@interface Teacher : NSObject{
NSString *name;
NSString *workNumber;
}
定義實(shí)例變量的方法,說(shuō)實(shí)話我在OC中用的不多,一般都是直接聲明成一個(gè)屬性酗昼。
這種方式存在一個(gè)問(wèn)題就是對(duì)象的定義是在編譯階段的,如果需要訪問(wèn)某個(gè)對(duì)象梳猪,結(jié)果都是編譯器直接去內(nèi)存區(qū)該對(duì)象存儲(chǔ)的地方來(lái)進(jìn)行訪問(wèn)麻削。這樣的方式看來(lái)沒(méi)什么問(wèn)題,但是但我想添加一個(gè)新實(shí)例變量在name上方的時(shí)候春弥,就不起作用了呛哟。
比如新聲明如下:
@interface Teacher : NSObject{
NSDate *birthDay;
NSString *name;
NSString *workNumber;
}
以上是OC中常見(jiàn)的定義實(shí)例變量的方法。
之前指向name的offset現(xiàn)在指向了birthDay匿沛,如果不進(jìn)行重新編譯扫责,那么數(shù)據(jù)訪問(wèn)就會(huì)錯(cuò)亂。
為了解決這個(gè)問(wèn)題逃呼,OC采用的方法是存儲(chǔ)這個(gè)offset鳖孤,當(dāng)變量改變的時(shí)候,offset也進(jìn)行相應(yīng)的升級(jí)抡笼。因此每次訪問(wèn)的時(shí)候苏揣,offset都是最新的,不會(huì)造成數(shù)據(jù)錯(cuò)亂推姻。
屬性
我的理解是平匈,屬性是在實(shí)例變量的基礎(chǔ)上,多封裝了一層訪問(wèn)方法及變量屬性拾碌。
關(guān)于Setter和Getter方法也不再贅述吐葱。
一般定義完屬性之后,屬性的訪問(wèn)方法都是系統(tǒng)自動(dòng)生成的校翔,雖然在你的代碼中看不到弟跑,但如果不自己重寫(xiě),她們也是存在的防症。
如果不想使用系統(tǒng)生成的訪問(wèn)方法曹铃,你可以自己實(shí)現(xiàn)方法。只實(shí)現(xiàn)其中一個(gè)方法的話青自,比如重寫(xiě)Getter堪遂,那么Setter還是系統(tǒng)幫你寫(xiě)好的方法阻课。
如果真的不想使用任何系統(tǒng)生成的訪問(wèn)方法,那么需要使用@dynmaic關(guān)鍵字, 這個(gè)關(guān)鍵字我們可以在使用CoreData生成類(lèi)文件的時(shí)候看到,類(lèi)的所有屬性都是@dynamic打頭吞加。表示屬性的訪問(wèn)方法是動(dòng)態(tài)生成的。
屬性的內(nèi)存引用修飾
- assign 對(duì)一些特定的純量對(duì)象類(lèi)使用尽狠,比如CGFloat衔憨,NSInteger
下面會(huì)牽扯到一些引用計(jì)數(shù)的知識(shí),假設(shè)A有一個(gè)屬性b袄膏,C也有一個(gè)屬性d - strong
賦值時(shí):A.b = C.d,此時(shí)內(nèi)存中b = d践图,b引用計(jì)數(shù)+1 = 2
A持有b,C持有d沉馆, C被釋放時(shí)码党,d沒(méi)有釋放,因?yàn)閎=d斥黑, A持有b揖盘。
- weak
賦值時(shí):A.b = C.d,此時(shí)內(nèi)存中b = d,因?yàn)槁暶鳛閣eak锌奴,b引用計(jì)數(shù)+0 = 1
A不持有b扣讼,C持有d, C被釋放時(shí)缨叫,d釋放,因?yàn)閎=d荔燎, A不持有b耻姥,b的計(jì)數(shù)清零。 - unsafe_unretained
基本和Weak一樣有咨,不持有對(duì)象琐簇,與Weak不同之處在于:
假設(shè)A中有一個(gè)unsafe_unretained的b,A被釋放后座享,b卻不會(huì)被釋放婉商,可能會(huì)造成野指針的問(wèn)題。 - copy
與strong類(lèi)似渣叛,表示持有對(duì)象丈秩,不同的是實(shí)際上是進(jìn)行了一次復(fù)制(對(duì)象必須遵守NSCopy協(xié)議)。
關(guān)于Copy和Strong的不同淳衙,下面舉個(gè)例子:
@interface Teacher : NSObject
@property (nonatomic, strong) NSMutableArray *sampleArray;
//@property (nonatomic, copy) NSMutableArray *sampleArray;
@end
聲明Teacher有一個(gè)可變數(shù)組對(duì)象為strong
以上兩行屬性聲明我們分別是Copy類(lèi)和Strong類(lèi)蘑秽,然后分別執(zhí)行以下測(cè)試代碼:
NSMutableArray *array = [@[@"a",@"b",@"c"]mutableCopy];
Teacher *tea = [[Teacher alloc] init];
tea.sampleArray= array;
[array addObject:@"d"];
NSLog(@"ArrayData:%@ \n teacherArrayPosition:%p \n reallyArrayPostion:%p",tea.sampleArray,tea.sampleArray,array);
Strong的時(shí)候輸出如下:
Copy的時(shí)候輸出如下:
可以看到Strong知識(shí)做了一次指針的引用饺著,而Copy是真正重新開(kāi)辟了一塊內(nèi)存空間去存儲(chǔ)變量。
所以使用Strong去修飾的缺點(diǎn)在于肠牲,對(duì)象可能會(huì)因?yàn)橐脤?duì)象的改變而發(fā)生改變幼衰,就像代碼測(cè)試所示,而Copy不會(huì)缀雳。
- assign和retain
其實(shí)我覺(jué)得這兩個(gè)是寫(xiě)法遺留的問(wèn)題渡嚣,其實(shí)assign也可以用于指針對(duì)象,作用相當(dāng)于weak肥印,retain相當(dāng)于strong识椰。
assign和retain在Xcode4.3之前使用,4.3之后就還是使用weak和strong吧竖独。
屬性與方法的統(tǒng)一
當(dāng)我們?cè)趯傩灾胁捎昧颂厥獾男揎椃脑捒氵耄热鏑opy,那我們可能需要在屬性的訪問(wèn)方法中對(duì)其進(jìn)行處理莹痢。
比如以下聲明:
@property (nonatomic, copy) NSString *name;
- (instancetype)initWithName:(NSString *)name;
在實(shí)現(xiàn)文件中我們就需要這么寫(xiě)來(lái)保持和修飾的統(tǒng)一性:
- (void)setName:(NSString *)name
{
_name = [name copy];
}
- (instancetype)initWithName:(NSString *)name
{
if (self = [super init]) {
_name = [name copy];
}
return self;
}
但實(shí)際上來(lái)說(shuō)种蘸,我們并不需要對(duì)遵守NSCopying協(xié)議的對(duì)象(比如NSArray,NSString)做這么麻煩的處理竞膳,系統(tǒng)會(huì)自動(dòng)幫我們處理好copy航瞭,所以以上只是舉個(gè)例子。如果想讓自定義對(duì)象支持copy坦辟,還是需要上面這么寫(xiě)刊侯,還要讓對(duì)象遵守NSCopying協(xié)議并實(shí)現(xiàn)copy方法。
還有一個(gè)需要注意的地方在于锉走,不要再init方法中調(diào)用自己的屬性訪問(wèn)方法滨彻。
也就是上面代碼使用_name = [name copy]的原因。想要深究原因的話可以看看下面這篇文章:
為什么不要在init和dealloc函數(shù)中使用accessor
總結(jié)
- 1 @property語(yǔ)法提供了一種數(shù)據(jù)的封裝方式(生成Setter和Getter)
- 2 在寫(xiě)屬性修飾之前仔細(xì)思考該如何更合適的去修飾它(內(nèi)存方面循環(huán)引用等問(wèn)題)
- 3 屬性與方法統(tǒng)一
- 4 在iOS端使用nonatomic