在OC中,定義一個類的過程和C++相似,先有一個聲明,而後再實現相應的函數。不過C++比較自由,既能夠像Java同樣全部函數都在類內實現,也能夠不都在類內實現,將一部分函數或者所有函數轉移到類外實現。而在OC中這方面的規定較爲嚴格。即——只能在聲明中定義變量(亦或稱爲屬性),只能在類實現中實現方法(函數)。具體使用形式以下:設計模式
//Objective-C類的聲明 @interface 類名 : 父類名 <實現的協議1,實現的協議2, … > //定義變量、聲明方法 @end
從中能夠看出,OC和Java同樣,不容許多重繼承,而多重繼承的相似實現方式可使用協議,也可使用類目來進行。
通常而言,類的聲明寫在頭文件(h文件)中,由於OC在#import導入文件的時候,只容許導入頭文件,因此在頭文件中定義的變量(屬性)和方法(函數)都是對其餘文件可見的。數組
OC中類的實現用於實如今聲明中或者擴展中定義的方法(函數),類目實現用於實現類目聲明中定義的方法(函數)。前者的使用形式以下:安全
//Objective-C類的實現 @implementation 類名 //實現方法,禁止定義變量 @end
值得注意的是,能夠實現沒有在聲明中聲明的方法,由於通常只會導入h文件,因此這樣的方法是對其餘類隱藏的(相似於C++的私有函數),可是這些被隱藏的方法並不是是私有的,經過一些途徑還能夠訪問只在實現中實現的方法。可是Apple不建議您這樣作。
記住:不能在實現中定義變量。函數
OC中爲了簡化繼承結構,提出了一種更簡單的向現有類添加方法的手段,這被稱爲Category(類目)。Category是OC語言特有的,而且這種特性讓不少其餘語言爲之眼紅。Category能夠很方便的向現有的類添加方法,可是注意不能夠添加變量。Category不會構造出一個新的子類,因此它不是繼承關係,被添加的方法和原來在父類中的方法的地位等同,可是若是出現了覆蓋現象,則只能調用Category定義的方法。使用形式爲:學習
//Objective-C的類目聲明 @interface 類名 (類目名) //添加方法的聲明,禁止添加變量 @end
//Objective-C的類目實現 @implementation 類名 (類目名) //添加方法的實現 @end
請注意,Category並非一個類,你依然只能使用原有類的名字,可是經過這個類或者這個類的對象可使用全部Category中的全部方法,就好像他們本來就在類中被聲明和實現同樣,這無疑是很是方便的。ui
在OC中,除了可使用Category向現有的類添加方法以外,還可使用Extension(擴展),在形式上,Extension就好像一個匿名的Category,可是Extension容許你向類中添加變量和方法,並且Extension不須要單獨編寫實現,須要實現的方法應該直接寫在原有的@implementation中,形式以下:編碼
//Objective-C的擴展聲明 @interface 類名 () //添加方法的聲明,添加變量 @end
上面添加的方法應該直接在類的實現中實現(參考Objective-C類的實現)
通常而言Extension定義在m文件中,因此Extension中的屬性和方法是不對外部和子類公開的,但這並非絕對的。實際上,由於在導入文件的時候只導入了h文件,並無導入m文件,因此實際狀況是,其餘文件中的類和對象根本就找不到m文件中的東西,由於原本它們就只導入了h文件。若是導入m文件的話,也是能夠訪問Extension中的函數的。可是大多數狀況下,系統編寫的類或者非開源的類不會公開m文件,也就是隱藏了方法的實現,這樣的話Extension中的函數天然就被隱藏了。設計
在OC中,也存在相似於C++和Java「構造函數」的東西,可是其機制和C++和Java語言有很大不一樣。OC中創建一個對象要分兩個步驟,一個是發送alloc消息分配空間,一個是發送init消息初始化對象。在OC中沒有真正的「構造函數」——也就是那個和類名相同的、無返回值的函數。在OC中,方法名以類名開頭(首字母小寫)的方法通常是靜態初始化方法,和Java中的工廠方法比較相似。例如上文中NSString*類型的代理
+(instancetype)stringWithFormat:
+(instancetype)stringWithCString:encoding:
等。這類函數能夠直接返回一個初始化好的對象。而另外一類以init開頭的方法通常是動態初始化方法,例如NSString *類型的-initWithFormat:、-initWithCString:encoding:等。這類方法必須在先發送過alloc消息的基礎上才能夠發送,不然會拋出異常。指針
此外,和C++、Java特別不一樣的一點是,OC的初始化方法是有返回值的,其返回值就是當前類的對象指針,例如NSString類型的初始化方法將返回NSString類型,在方法末要加上return self。可是在OC繼承中,由於OC的初始化方法就是普通方法,因此也會一併繼承到子類中,若是不覆蓋繼承來的初始化方法,那麼這個方法就會返回錯誤的類型——也就是返回一個父類對象指針。Apple爲了解決這個問題,引入了instancetype類型,這個類型能夠自動返回該類的對象指針。因此咱們在本身編寫初始化方法的時候,一概使用instancetype類型做爲返回值。注意:instancetype類型和id類型是不一樣的,instancetype類型是當前類的對象指針,而id類型是任意類型的對象指針。
在定義一個屬性或者一個變量的時候,能夠指定變量的引用計數特性,包括retain、assign、copy、strong、weak、unsafe_unretained,這些屬性都和Objective-C的引用計數機制有關。
定義引用計數屬性的方式:
//使用property: @property (特性) 類型 屬性名; //不使用property: __特性 類型 變量名;
下面詳細講解引用計數機制:OC爲了解決C語言內存管理的問題,使用引用計數的方法來管理內存。首先咱們知道,在OC中全部的對象都是指針,對象所佔用的內存都是動態分配產生的,按照C和C++的原理,這些內存須要用戶本身去管理。可是在OC中,只要使用了引用計數,用戶就無需使用手動管理內存。咱們在程序中申請一片空間用於存放對象的時候,系統會自動爲該空間創建引用計數,每有一個指針指向這塊空間,該空間的引用計數就加1,當一個指針再也不指向該內存空間的時候(改成指向nil或者指向其餘內存空間),這塊空間的引用計數就降爲0,被當即釋放,同時指針也不會指向任意位置內存,而是指向nil來保證安全。這就是引用計數機制。在iOS5以及更高版本引入了ARC機制,這樣咱們能夠更方便的管理內存。上述關鍵字對屬性或者變量的引用計數特性的影響以下:
retain:使用引用計數,在函數參數傳遞時,使用的是指針傳遞,引用計數+1,引用計數=0的時候對象將釋放,這是除NSString*之外的類型的默認設置,只能用於對象。
copy:參數傳遞時拷貝對象,在函數參數傳遞時,使用的是值傳遞,原有對象的引用計數不變,直接爲形參創建新的內存空間,引用計數=0的時候對象將釋放,這是NSString*類型的默認設置,只能用於對象。
strong:強指針類型,使用引用計數,strong是ARC機制的關鍵字,本質上和retain沒有區別。
weak:弱指針類型,使用引用計數,weak是ARC機制的關鍵字,和retain相似,可是使用weak指針能夠保證不會出現強引用循環現象(若是不能理解的話就隨便看看吧)。
**強引用循環:兩個strong指針互相指向的時候,這兩塊內存空間的引用計數都沒法降爲0,這時候就會發生內存泄漏,這稱爲強引用循環。將其中一個指針改成weak指針便可解決此問題。unsafe_unretained:不使用引用計數,徹底按C和C++的模式管理。
assign:不使用引用計數,值傳遞,只能用於NSInteger等基本類型。
Objective-C的Protocol(協議)相似於Java的接口,是一些方法聲明的集合,在協議中能夠規定若干方法,方法分爲@required類型(默認爲此類型)和@optional類型,前者是必須實現的,後者是可選實現的。一個類能夠實現多個協議,可是隻能繼承一個父類,在實現協議的時候,必須實現協議中規定的@required方法,不然會出現警告。協議實際上能夠理解爲「多個類之間的約定」。經過實現相同的協議,一個類能夠安全的調用另外一個類的某些方法,只要他們都位於協議中而且是@requierd的。在UITableView的實現中就用到了這種關係,在UITableView類中會自動調用一些方法來設置UITableView的一些屬性,而這些屬性應該在UITableView對應的視圖控制器中進行設置,因此要將這些方法放入對應的UIViewController類中,如何確保這個類中確實存在這些方法,在調用的時候不會出錯呢?只須要規定一個協議,把須要調用的方法放入其中,讓使用UITableView的視圖控制器去實現便可。這種方式被稱爲委託設計模式。詳見Delegate設計模式
協議的定義:
@protocol 協議名 <父協議> @required //必須實現的方法聲明 @optional //可選實現的方法聲明 @end
注意:協議中不能夠實現方法,只能聲明,方法的實現應該交給實現這個協議的類來完成。
協議的實現
@interface 類名 : 父類名 <實現的協議1,實現的協議2, …> … @end
@implementation 類名 //實現協議中規定的方法 @end
使用IBAction的時候,其實是用到了Taget-Action設計模式。這種設計模式的工做方式是:當某個特定的Event發生的時候,發送者(sender)會向一個指定的目標(target)發送一個以前設定好的IBAction消息。例如當一個UIButton被點擊的時候,該按鈕就是發送者(sender),經過定義IBAction,將其目標聲明爲對應的UIViewController,同時UIButton調用了UIViewController中對應的IBAction消息,這就是Target-Action設計模式的工做方式。
在Target-Action設計模式中,針對不一樣的Event,須要定義不一樣的IBAction方法。實現相似的功能還可使用Delegate(委託)設計模式。這種設計模式的原理是,本來的消息發送者將具備一個delegate屬性,能夠將其餘類定義成消息發送者的delegate。在該對象的某個事件發生的時候,由於該對象可能不能本身處理這個事件,因此它就經過「委託」的方式,調用Delegate方法來實現相應的功能,這種設計模式稱爲Delegate設計模式,是經過協議來實現的。
例如當UITableView的某個單元格被點擊的時候,實際上UITableView自身是沒法處理這個事件的,單元格被點擊以後要作什麼應該由其對應的UIViewController來決定,這時候就把UITableView的delegate屬性設置爲這個視圖控制器,而且這個視圖控制器來實現UITableView的一個協議(協議中規定了做爲一個合格的委託應該實現的方法)。這樣在視圖控制器類裏實現對應的代理方法(委託方法),就完成了這一事件的處理。
OC中全部類的共同父類是NSObject*類型,其中包含了一些基本的方法,例如alloc和init等。
OC的字符串類型:NSString*類型,默認屬性是copy,能夠直接用賦值語句來建立一個字符串,也可使用初始化方法建立,通常使用如下幾種:
+(instancetype)stringWithFormat:(nonnull NSString *), …
該方法能夠用各類類型的數據生成一個NSString*對象
+(instancetype)stringWithCString:(nonnull const char *) encoding:(NSStringEncoding)
該方法可使用encoding指定的編碼,利用一個const char類型的C風格字符串初始化一個NSString對象
還有不少初始化方法,能夠根據Xcode的自動提示或者API文檔學習,將上述方法中的string改成init,就是對應的動態方法(帶「-」號的)。上面的都是靜態方法,在實際應用過程當中,靜態方法的使用更爲普遍。
還有一些方法能夠將字符串轉化爲數字,通常使用如下幾個:
-(NSInteger)integerValue
該方法能夠將字符串轉換爲整數,若是向含有非數值的字符串發送該消息,則會自動截斷非數值部分。
-(int)intvalue
和上面的方法相似,只不過是轉化爲int類型(NSInteger在64位機上是long)。
-(double)doubleValue
和上面的方法相似,只不過是轉化爲double類型。
NSString是常量字符串,其值不可改變,能夠改變值的字符串類型是NSMutableString類型,可是咱們形式上也能夠經過賦值「改變」一個NSString字符串的值,可是這種改變其實是從新申請了一個對象,詳見引用計數機制。
OC和Java同樣,數組都做爲類來出現,這樣的好處就是可使用各類方法,擴展數組的功能。OC中的數組類型也分NSArray和NSMutableArray類型,區別和上面的字符串類型相同,一個是常量數組,一個是可變數組(實際上就是鏈表)。這裏的可變指的是數組的長度,也就是說NSMutableArray的長度是能夠隨時擴展的,而NSArray的長度和C++同樣,不能擴展。下面介紹NSArray*的經常使用方法:
初始化方法:
+(instancetype)arrayWithObjects:(nonnull id), … , nil
這個方法能夠返回一個數組,並經過後面的參數向數組中添加元素
+(instancetype)array
創建一個空數組
-(id)objectAtIndex:(NSUInteger)
返回以給定無符號數爲下標的元素,返回值是任意對象的指針
-(id)objectAtIndexes:(nonnull NSIndexSet*)
返回一個元素組(多個元素),NSIndexSet*是一個元素組類型,在介紹UITableView時會介紹。
NSMutableArray*的經常使用方法:
+(instancetype)arrayWithObjects:(nonnull id), … , nil
這個方法能夠返回一個數組,並經過後面的參數向數組中添加元素
-(id)objectAtIndex:(NSUInteger)
返回以給定無符號數爲下標的元素,返回值是任意對象的指針
+(instancetype)array
創建一個空數組
-(void)addObject:(nonnull id)
向數組中插入一個元素(添加到末尾)
-(void)removeObjectAtIndex:(NSUInteger)
刪除數組中指定的元素