前言
?? ?在實(shí)際的開(kāi)發(fā)過(guò)程中,繼承和類(lèi)別都會(huì)得到很多用處。對(duì)于界面相似度很高的情況下,使用繼承可以節(jié)省很多代碼和設(shè)置,只需要在子類(lèi)中重寫(xiě)父類(lèi)中的方法,或者增加新的子類(lèi)方法即可,代碼非常的簡(jiǎn)潔維護(hù)起來(lái)也很方便。下面小節(jié)下相關(guān)的知識(shí),供需要的朋友查看。? ? 在Objective-C中,給一個(gè)類(lèi)擴(kuò)展一個(gè)其它方法,有兩種實(shí)現(xiàn)方式:類(lèi)別和繼承。
?繼承
?這個(gè)是面向?qū)ο笳Z(yǔ)言都有的一個(gè)特性,子類(lèi)會(huì)繼承父類(lèi)的方法和屬性以及成員變量。? 這里說(shuō)的方法需要在 父類(lèi)中的 .h中聲明,子類(lèi)才可以使用super 調(diào)用父類(lèi)的方法,可以繼承過(guò)來(lái)父類(lèi)的一切屬性,可以使用父類(lèi)的成員變量。
? ? .h 文件相當(dāng)于一個(gè)對(duì)外公開(kāi)的 head ,是因?yàn)?oc 中無(wú)法導(dǎo)入 .m 文件,只能導(dǎo)入.h 文件,所有子類(lèi)中需要用到父類(lèi)中導(dǎo)入的頭文件的話,這個(gè)頭文件需要在 父類(lèi)的.h? 中導(dǎo)入,子類(lèi)無(wú)法調(diào)用 父類(lèi) .m 中導(dǎo)入的頭文件 和聲明的 成員變量。所以把 .m 文件中的東西相當(dāng)于是 私有的,不會(huì)被非本類(lèi)的對(duì)象所調(diào)用。
? ? ?在繼承中需要注意的是:重寫(xiě)的這個(gè)方法在父類(lèi)中執(zhí)行時(shí)會(huì)替換掉原來(lái)的方法的(就算子類(lèi)中沒(méi)有調(diào)用這個(gè)新重寫(xiě)的方法,這個(gè)新方法也已經(jīng)被執(zhí)行了),一般自己不調(diào)用這個(gè)重寫(xiě)的方法,子類(lèi)一般只調(diào)用新加的方法。
? 在 .h 中聲明成員變量,又不想被子類(lèi)調(diào)用,可以對(duì)這個(gè)成員變量進(jìn)行限定如:
{
@private
NSMutableArray*modelArray;
}
@private 私有成員,只有當(dāng)前類(lèi)可以訪問(wèn);
@protected 受保護(hù)成員,只有當(dāng)前類(lèi)或子類(lèi)可以訪問(wèn)(如果沒(méi)有添加任何修飾則默認(rèn)為@protected);
@public 公共成員,所有類(lèi)均可訪問(wèn);
類(lèi)別category
這是Objective-C語(yǔ)言的一個(gè)特性,可以在不改變類(lèi)名和原來(lái)類(lèi)的實(shí)現(xiàn)的前提下,實(shí)現(xiàn)對(duì)類(lèi)的方法擴(kuò)展。
以下兩種方式最好使用類(lèi)別。
1)針對(duì)系統(tǒng)提供的一些類(lèi),例如:NSString,NSArray,NSNumber等類(lèi),進(jìn)行方法擴(kuò)充的時(shí)候。
2)類(lèi)別支持開(kāi)發(fā)人員針對(duì)自己構(gòu)建的類(lèi),把相關(guān)的方法分組到多個(gè)單獨(dú)的文件中,對(duì)于大型而復(fù)雜的類(lèi),這有助于提高可維護(hù)性,并簡(jiǎn)化單個(gè)源文件的管理。
對(duì)于以下情況,無(wú)法使用類(lèi)別,必須使用繼承。
1)新擴(kuò)展的方法與原方法同名,但是還需要使用父類(lèi)的實(shí)現(xiàn)。因?yàn)槭褂妙?lèi)別,會(huì)覆蓋原類(lèi)的實(shí)現(xiàn)(繼承也會(huì)覆蓋,就是所謂的重寫(xiě),但是可以在重寫(xiě)的時(shí)候調(diào)用 ?父類(lèi)的同名方法,而類(lèi)別不能),無(wú)法訪問(wèn)到原來(lái)的方法。
2)擴(kuò)展類(lèi)的屬性,這個(gè)類(lèi)別無(wú)法做到。
OC中的子類(lèi)可以擁有和父類(lèi)相同名稱(chēng)的方法,在子類(lèi)調(diào)用時(shí),優(yōu)先去自己的內(nèi)部尋找,如果沒(méi)有則一層一層的往上找;
(4)OC語(yǔ)言是單繼承語(yǔ)言。在OC語(yǔ)言中,基本上所有類(lèi)的根類(lèi)都是NSObject類(lèi)。
提示:重寫(xiě)即子類(lèi)重新實(shí)現(xiàn)了父類(lèi)中的某個(gè)方法,覆蓋了父類(lèi)以前的實(shí)現(xiàn)。
提示:每個(gè)類(lèi)中都有一個(gè)super class指針,該指針指向自己的父類(lèi)。對(duì)象中有一個(gè)isa指針,該指針指向調(diào)用該對(duì)象的類(lèi)。
繼承的好處:
(1)抽取出了重復(fù)的代碼
(2)建立了類(lèi)和類(lèi)之間的聯(lián)系
繼承的缺點(diǎn):耦合性太強(qiáng)
屬性
在OC中定義變量,可以自己來(lái)定義變量的setter方法來(lái)設(shè)置變量值,用getter方法來(lái)獲取變量值,但是當(dāng)變量數(shù)量增多時(shí),還采用手動(dòng)添加setter/getter方法來(lái)操作變量,就會(huì)使得程序代碼量大大增加,于是就出現(xiàn)了 @property 來(lái)快速聲明設(shè)置獲取變量的值的方法,這也許就是 ?@property @synthesize/@dynamic 設(shè)計(jì)的本意。
@property是給編輯器看的。就算你不聲明@property,在obj的@implenmention下寫(xiě)好valueA和setValueA,還是可以obj.valueA賦值或取值,但是沒(méi)有自動(dòng)聯(lián)想。
只聲明@property而不去實(shí)現(xiàn),在Xcode4.4以后會(huì)自動(dòng)幫你生成get和set方法
本質(zhì)上來(lái)講,屬性也會(huì)幫你定義一個(gè)成員變量,并根據(jù)屬性的聲明自動(dòng)生成getter/setter 方法,其中setter 方法根據(jù)屬性(property)的屬性(attribute)來(lái)提供不同的內(nèi)存管理策略。
@property是一個(gè)屬性訪問(wèn)聲明以及聲明getter,setter方法,
擴(kuò)號(hào)內(nèi)支持以下幾個(gè)屬性:(getter=getterName,setter=setterName,設(shè)置setter與getter的方法名,retain,copy,assign.......)
在聲明property屬性后,有2種實(shí)現(xiàn)選擇
@synthesize? 作用是實(shí)現(xiàn)屬性的,如getter,setter方法. (通過(guò)類(lèi)別和runtime 的對(duì)相關(guān)聯(lián)技術(shù)生成新的屬性時(shí),無(wú)法使用這個(gè)這個(gè)設(shè)置,只能使用@dynamic)
編譯器期間,讓編譯器自動(dòng)生成getter/setter方法。
當(dāng)有自定義的存或取方法時(shí),自定義會(huì)屏蔽自動(dòng)生成該方法
@dynamic
告訴編譯器,不自動(dòng)生成getter/setter方法,避免編譯期間產(chǎn)生警告
然后由自己實(shí)現(xiàn)存取方法
如果@synthesize和@dynamic都沒(méi)寫(xiě),那么默認(rèn)的就是@syntheszie var = _var;
我們來(lái)看一下屬性的本質(zhì)和進(jìn)化過(guò)程:
原始形態(tài):
? ? 定義一個(gè)實(shí)例變量:int age;
? ? 先在.h文件中聲明setter和getter器
? ? -(void)setAge:(int)newAge;
? ? ?-(int)age;
然后在.m文件中具體實(shí)現(xiàn)
-(void)setAge:(int)newAge
{
? ? ?age=newAge;
}
-(int)age
{
?return?age;
}
這樣的話就可以跟屬性一樣使用了。
//比如上面的聲明是一個(gè)Person類(lèi)
Person*person=[[Person?alloc]init];
[person?setAge:13];
int age=[person?age];
//點(diǎn)調(diào)用
person.age=13;??//.調(diào)用出現(xiàn)在=號(hào)左邊,相當(dāng)于setter
intage=person.age???//.調(diào)用出現(xiàn)在=號(hào)的右邊,相當(dāng)于getter
NSLog(@"%i",person.age);//這也是getter
setter和getter的改進(jìn)寫(xiě)法:
每次要為一個(gè)屬性寫(xiě)上getter和setter,不得不手十分麻煩,所以有了更簡(jiǎn)單的寫(xiě)法,
在.h文件里,直接這樣寫(xiě),表示聲明了一個(gè)實(shí)例屬性和它的getter和setter器
@property?int?age;
然后在.m文件中這樣寫(xiě),
@synthesize?age;
表示實(shí)現(xiàn)setteer和getter,這樣,就可以和以前一樣調(diào)用getter和setter了。
setter和getter的改進(jìn)優(yōu)化:
可以看到,getter器的方法名直接就是變量名,方法名和變量名一樣,容易讓人迷糊,所以,可以這樣優(yōu)化。
在.h文件中依然這樣聲明
@property?int?age;
在.m文件中,這樣去寫(xiě),
@synthesizeage=_age;?//加上一個(gè)_
//這么,我們就可以去使用_age???和使用age一樣
-(void)show
{
NSLog(@"%i",_age);
}
可以看出來(lái),在Objective-C中setter器沒(méi)什么區(qū)別,不過(guò)getter器的方法名缺少了get,因?yàn)間et...在Objective-C有別的用處,所以getter器直接寫(xiě)的就是變量名。
? ? ?1. 如果只聲明一個(gè)屬性a,不使用@synthesize實(shí)現(xiàn):編譯器會(huì)使用_a作為屬性的成員變量(如果沒(méi)有定義成員變量_a則會(huì)自動(dòng)生成一個(gè)私有的成員變量_a;如果已經(jīng)定義了成員變量_a則使用自定義的成員變量_a。注意:如果此時(shí)定義的成員變量不是_a而是a則此時(shí)會(huì)自動(dòng)生成一個(gè)成員變量_a,它跟自定義成員變量a沒(méi)有任何關(guān)系);
? ? ? 2.如果聲明了一個(gè)屬性a,使用@synthesize a進(jìn)行實(shí)現(xiàn),但是實(shí)現(xiàn)過(guò)程中沒(méi)有指定使用的成員變量(例如上面birthday):則此時(shí)編譯器會(huì)使用a作為屬性的成員變量(如果定義了成員變量a,則使用自定義成員變量;如果此時(shí)沒(méi)有定義則會(huì)自動(dòng)生成一個(gè)私有的成員變量a,注意如果此時(shí)定義的是_a則它跟生成的a成員變量沒(méi)有任何關(guān)系);
? ? ? 3.如果聲明了一個(gè)屬性a,使用@synthesize a=_a進(jìn)行實(shí)現(xiàn),這個(gè)過(guò)程已經(jīng)指定了使用的成員變量:此時(shí)會(huì)使用指定的成員變量作為屬性變量;(那還不如不寫(xiě)這個(gè)?@synthesize ..)
有了上面的總結(jié),相信理解上面的代碼并不難,通常在實(shí)際開(kāi)發(fā)過(guò)程中我們要么直接在@property中聲明不使用@synthesize;要么使用過(guò)程中指定具體的成員變量。
此外再次強(qiáng)調(diào)一下,通過(guò)上面的方式定義變量的本質(zhì)還是生成對(duì)應(yīng)的gettter、setter方法(只是這個(gè)步驟編譯器幫你完成了),如果通過(guò)@property定義了屬性,同時(shí)在.m中又自定義實(shí)現(xiàn)了對(duì)應(yīng)方法,則會(huì)使用自定義方法。
定義setter的語(yǔ)義
nonatomic??禁止多線程,變量保護(hù),提高性能。
atomic ? ?是Objc使用的一種線程保護(hù)技術(shù),基本上來(lái)講,是防止在寫(xiě)未完成的時(shí)候被另外一個(gè)線程讀取,造成數(shù)據(jù)錯(cuò)誤。而這種
機(jī)制是耗費(fèi)系統(tǒng)資源的
assign ? 此標(biāo)記說(shuō)明設(shè)置器直接進(jìn)行賦值 ,賦值特性,不涉及引用計(jì)數(shù),弱引用對(duì)基礎(chǔ)數(shù)據(jù)類(lèi)型 (NSInteger,CGFloat)和C數(shù)據(jù)類(lèi)型(int, float,double, char)等等。
如果你要一個(gè)屬性使用assign,且這個(gè)類(lèi)符合NSCopying協(xié)議.
retain ? ?對(duì)其他NSObject和其子類(lèi)對(duì)參數(shù)進(jìn)行release舊值,再retain新值,新對(duì)象的引用計(jì)數(shù)+1;
指定retain會(huì)在賦值時(shí)喚醒傳入值的retain消息。此屬性只能用于Objective-C對(duì)象類(lèi)型,而不能用于Core
Foundation對(duì)象。(原因很明顯,retain會(huì)增加對(duì)象的引用計(jì)數(shù),而基本數(shù)據(jù)類(lèi)型或者Core Foundation對(duì)象都沒(méi)有引用計(jì)數(shù)——譯者注)。
注意: 把對(duì)象添加到數(shù)組中時(shí),引用計(jì)數(shù)將增加對(duì)象的引用次數(shù)+1。
copy ? 對(duì)NSString 它指出,在賦值時(shí)使用傳入值的一份拷貝。拷貝工作由copy方法執(zhí)行,此屬性只對(duì)那些實(shí)行NSCopying協(xié)議的對(duì)象類(lèi)型有效,表示兩個(gè)對(duì)象內(nèi)容相同,新的對(duì)象retain為1 ,與舊有對(duì)象的引用計(jì)數(shù)無(wú)關(guān)。
weak? ? weak比assign多了一個(gè)功能,當(dāng)對(duì)象消失后自動(dòng)把指針變成nil,好處不言而喻。弱引用除了不決定對(duì)象的存亡外,其他與強(qiáng)引用相同。即使一個(gè)對(duì)象被持有無(wú)數(shù)個(gè)若引用,只要沒(méi)有強(qiáng)引用指向他,那麼其還是會(huì)被清除。
retain? ?是指針拷貝,copy 是內(nèi)容拷貝。
iOS 5 中對(duì)屬性的設(shè)置新增了strong 和weak關(guān)鍵字來(lái)修飾屬性(iOS 5 之前不支持ARC)
strong ? 用來(lái)修飾強(qiáng)引用的屬性,一塊內(nèi)存(一個(gè)對(duì)象)當(dāng)沒(méi)有 strong 類(lèi)型的指針指向它時(shí),它就會(huì)被釋放;ARC中使用,與MRC中retain同義,使用之后,計(jì)數(shù)器+1。
官方文檔中有這樣的示例代碼:// The following declaration is a synonym for: @property(retain) MyClass *myObject;@property(strong) MyClass *myObject;表示了strong和retain是同義詞。
weak? ? 用來(lái)修飾弱引用的屬性,當(dāng)一塊內(nèi)存(一個(gè)對(duì)象)被釋放時(shí),指向它的 weak 類(lèi)型指針就會(huì)被釋放并賦值為 nil。
所以,如果一般情況下,我們都不希望字串的值跟著str變化,所以我們一般用 copy 來(lái)設(shè)置string的屬性。如果希望字串的值跟著賦值的字串的值變化,可以使用 strong,retain。當(dāng)然這也只是針對(duì) NSMutableString,因?yàn)槿绻?NSString 那么 copy 與 retain 的效果是一樣的。
這里需要提一下,如果一個(gè)對(duì)象作為屬性時(shí),定義setter的語(yǔ)義使用了copy字段,那么需要遵循 <NSCopying>協(xié)議,并且需要重寫(xiě) copyWithZone 方法。否則會(huì)cash。
NSZone 是蘋(píng)果對(duì)內(nèi)存分配和釋放的優(yōu)化方式。NSZone不是一個(gè)對(duì)象;它是一個(gè)難懂的C結(jié)構(gòu),它被用于紀(jì)錄關(guān)于內(nèi)存處理(管理)一系列對(duì)象的信息。
- (id)copyWithZone:(NSZone*)zone
{
? ? id ? copy = [[[self ?class]alloc]init];
? ?if(copy){
? ? // self.imageName 是 當(dāng)前的屬性
? ? ?[copy ? setImageName:[self.imageName copyWithZone:zone]];
? ?}
? ? ? ?return ? copy;
}
一些需要注意的知識(shí)
1.實(shí)例方法/動(dòng)態(tài)方法
2.靜態(tài)方法/類(lèi)方法
靜態(tài)方法在堆上分配內(nèi)存(釋放工作由程序員控制),實(shí)例方法在棧上(是由編譯器自動(dòng)管理)
靜態(tài)方法常駐內(nèi)存,實(shí)例方法不是,所以靜態(tài)方法效率高但占內(nèi)存
本文參考文章: