Object-C 的特點

【轉自】點擊打開鏈接

1Cocoa是什麼?Cocoa是使用OC語言編寫的工具包,裏面有大量的類庫、結構體,說白了其實就相當於java中的標準APIC++中的標準庫。OC中沒有命名空間的概念,所以使用加前綴來防止命名衝突,因此你會看到大量的以NS 爲前綴的類名、結構體、枚舉等。

 

2Cocoa框架由Foundation KitApp Kit兩部分組成,前者是基礎工具庫,後者主要是UI庫、高級對象等。

 

3static 標識的類變量定義在接口的外面,類變量只能本類訪問,除非提供類方法給外部訪問這個類變量。

 

4@語法是OC特有的一種語法,C是沒有的。

 

5OC中只有類的成員變量纔有訪問權限控制,@public、@protected、@private,默認是@protected,類變量、類方法、成員方法是沒有訪問修飾符的,所有的方法都是public的,所有的類變量都是私有的。

 

6OC中的類方法只能類調用,如果使用對象調用就會報錯,而java這只是一個警告而已。

 

7OC中定義類的@interfacejava中的interface不是一回事,OC@protocoljava中的interface纔是一碼事。@interfacejavaC++ class關鍵字差不多,在OCC++中,都習慣將類定義寫在頭文件裏,而java卻根本沒有頭文件的概念,至於爲什麼有這樣的差別,我想是爲了OCC++編譯器方便,大多數時候編譯器只需要知道頭文件類的定義就知道這個類有哪些屬性和方法了。

 

8get爲前綴的方法在OC中有特殊的意義,所以儘量使用成員變量名稱來作爲getter方法的函數名。

 

9OC是動態語言,所以即便是@interface中沒有定義的方法在.m文件中實現了也是OK的,一般我們都是給別人提供頭文件,這種情況就相當於把方法變相的私有化了,對於我這種喜歡在寫代碼過程中隨時加方法但又不想動頭文件的人來說還是比較爽的。

 

10、在OC中所有對象的存取都是用指針,C++中還有引用,OC中沒有,我寧願你強迫我使用一種方法,也不願你提供給我兩種方法我卻不知道使用哪一種方法的好。

 

11OC的方法定義和調用算是一大“特色”:

方法的定義:-(返回類型方法名:(參數1類型)參數1變量 參數2標籤:(參數2類型)參數2變量...

[類或者實例的指針 方法名: 參數1 標籤2: 參數2… …]

爲了好看,第一個參數一般不加標籤名,當然,標籤名都可以隱藏的,但不建議這樣做,因爲當你接手了一個離職的人程序,其中的JAVA 程序調用了一個有五個甚至更多的參數的方法,但是你手裏沒有這個方法的API,那麼你很難猜得出來這五個參數到底都幹什麼用的,但是Objective-C調用的時候,每個參數前面都必須有方法的標籤名,這樣你便能很容易的從標籤名看出這個參數是什麼意思。

 

12、調用類方法:

[Fraction t];

[[Fraction class] t];

Class clazz=[Fraction class];[clazz t];

class 來自於NSObject,相當於JAVA 中的getClass()方法,也就是獲取這個類的Class 對象,

clazz 前面沒有*,這是因爲Class 已經是一個指針。另外這種嵌套調用的方式,你也要習

慣,這就和JAVA 中的A.b().c()沒有什麼區別。

獲取Class 有如下幾種方法:

[類或者對象 class]

[類或者對象 superclasss]

NSClassFromString(類名的字符串形式)

你也可以通過如下的函數把Class 轉換爲字符串形式:

NSStringFromClass(Class)

 

13OC中自定義類最好顯示繼承NSObject,可以獲得alloc、init、release等方法。

 

14OC中使用nil表示null,但跟java中的null還是有區別的,java中調用null的方法,會報臭名昭著的空指針異常,而OC不會,所以在OC你不必再爲空指針而煩惱。

 

15Cocoa中提供的很多函數和java中的api有很大的不一樣,java是純面向對象的,所有的方法都必須在類中定義,但OC是兼容C語言的,所以C中的面向過程思想在OC中也是行得通的,因此Cocoa中很多東西都不是對象,而是C語言的函數、結構體,比如NSLog()

 

16、對象的初始化

前面我們看到實例化對象最多的方法是:Fraction *frac=[[Fraction alloc] init];

這跟java不一樣,java對象創建只需要new一下,同時調用構造方法(實際上虛擬機層面分爲兩個步驟:new對象,執行<init>方法(包含構造方法)),但是OC中分爲兩步:分配內存(同時給變量賦初值)、初始化。

1)、alloc 是從NSObject 繼承而來的類方法,用於給對象分配存儲空間,所有的成員變量在此時對確定了自己的內存位置,並被賦初值,整數類型爲0,浮點數爲0.0,BOOL 爲NO,對象類型爲nil,alloc 方法返回對象的指針。

2)、init這個方法是從NSObject繼承而來的,你可以覆蓋它,當然init不是構造方法,只是一個普通方法而已,你甚至可以換成其他方法,只不過我們習慣在方法名前綴加上init

還記得java中的構造方法沒有返回值吧,所以爲了達到java這種效果:Test t = new Test(2);OC中需要你手動在普通方法(相當於構造方法)中return self

 

17NSObject中的description方法相當於javaObjecttoString方法,,用於獲取對象的字符串表示。唯一不同的是OC中需要使用格式化字符串%@,纔會觸發description被調用:

Fraction *frac=[[Fraction alloc] init];

NSLog(@"%@",frac);

 

18、Objective-C 的異常都繼承自NSException,當然NSException 本身也繼承自NSObject。使用下面的語句塊進行異常捕獲:

@try {  

      <#statements#>  

  }  

  @catch (NSException *exception) {  

      <#handler#>  

  }  

  @finally {  

      <#statements#>  

  }  

總體來說,OC中的異常體系和java中的異常體系差不多,唯一的差別就是java中有業務異常,意思就是說你必須捕獲他,如果不捕獲就會出現編譯錯誤,OC中的異常基本上都屬於java中的運行時異常,如果你沒有捕獲,發生了異常程序就會崩潰,在一些循環批任務中尤其要注意。

 

18OC中還有一個特色那就是他的弱類型id,他可以表示任何對象,實際上應該是利用了指針地址的通用性,由於OC中操作對象都必須是指針,而指針本身又是一串地址,所以通過指針可以指向一切不同的對象。

 

19、繼承(感覺和java差不多啊)

 

20、反射(這個和異常一樣,感覺跟java也很像)

 

21、選擇器(其實就是C中的函數指針,以及java中的Method類)

 

22、類別(Category),擴充類的功能,但不可以聲明新的成員變量。

類別的應用比較廣泛,譬如:第三方的Objective-C 庫RegexKitLite 就是對NSString、NSMutableString 做的類別,爲Objective-C 的字符類型增加了正則表達式的功能。

 

23協議@protocol,這個就是前面說的,相當於java中的interface,思想都是一種約定、規範,只是具體語法不一樣罷了。

 

24、終於到了內存管理了,擦,沒怎麼看懂,要好好找個專題弄懂。

 

25、字符串

-(BOOL) isEqualToString: (NSString*) s

比較兩個字符串是否相等,與JAVA 一致的地方是==比較指針,比較對象是否相同要用到equal 方法。

-(NSMutableString*) appendString: (NSString*) s

這與JAVA 的StringBuffer 的append 沒什麼區別。

 

26、數組

Cocoa 使用NSArray 表示數組,但是它不能存儲基本數據類型、enum、struct、nil,只能存儲Objective-C 的對象。

NSArray *array=[NSArray arrayWithObjects: @"One", @"Two", @"Three", nil];

從這個類方法arrayWithObjects 的定義可以看出,它使用nil 表示數組元素結束,這也是nil 不能存儲在NSArray 中的原因。

NSMutableArray 爲長度可變的數組,相當於JAVA 中的List

NSMutableArray *mArray=[NSMutableArray arrayWithCapacity: 10];

[mArray addObject: @"Apple"];//添加數組元素

NSEnumerator *e = [mArray objectEnumerator];//獲取數組的迭代器,相當於JAVA 中的Iterator,reserveObjectEnumerator 用於獲取反轉之後的數組迭代器。與JAVA 一致的地方是你在使用迭代器時,不能對數組進行添加、刪除操作。

for(NSString *ms in mArray){

NSLog(@"%@",ms);

}

//for-each 快速枚舉爲Objective-C 2.0 的新特性,Windows 上的GNUStep 並不支持。

 

27字典(哈希表)

NSDictionary 用於存儲key-value 的數據結構,與JAVA 中的Map 類似。

NSDictionary *dic=[NSDictionary dictionaryWithObjectsAndKeys: @"Apple", @"A", @"Google",@"G", nil];//dictionaryWithObjectAndKeys 後的可變參數,每兩個爲一個value-key,以nil 表示結束。

NSLog(@"%@",[dic objectForKey: @"A"]);//按照指定的key 查詢value

同樣的有NSMutableDictionary 表示長度可變的字典。

NSMutableDictionary *mDic=[NSMutableDictionary dictionaryWithCapacity: 10];

[mDic setObject: @"Apple" forKey: @"A"];//添加value-key 對

for(id key in mDic){

NSLog(@"%@ : %@",key,[mDic objectForKey: key]);

}

//快速迭代的for-each 循環

 

28哈希Set

NSSet 表示以hash 方式計算存儲位置的集合,與JAVA 中的HashSet 是一致的。在NSSet 中的每個對象都有一個唯一的hash 值,重複的對象將只能保留一個。因此,這引出了Objective-C中的對象比較問題,這需要你實現從NSObject 繼承而來的如下兩個方法:

- (BOOL) isEqual: (id) anObject;

- (NSUInteger) hash;

這與JAVA 的對象比較沒有什麼區別,兩個相等的對象必須有相同的hashCode,所以這兩個方法必須同時實現。

同樣的,NSMutableSet 表示長度可變的哈希Set。

 

29封裝類(相當於java的包裝器)

前面的幾個容器類的對象都不能存放基本數據結構、enum、struct、nil,怎麼辦呢?在JAVA中我們知道所有的基本數據類型都有對應的封裝類,例如:int---Integer、boolean---Boolean,使用封裝類可以把基本數據類型包裝爲對象,而封裝類本身又有方法可以返回原來的基本數據類型。Cocoa 使用NSValue 作爲封裝類。

NSRect rect=NSMakeRect(1,2,30,50);//這個是在前面提到過的一個表示矩形的結構體

NSValue *v=[NSValue valueWithBytes: &rect objCType: @encode(NSRect)];

//valueWithBytes 要求傳入包裝數據的地址,也就是變量中存儲的數據的首地址,我們依然使用C 語言的&作爲地址運算符,計算指針存儲的首地址。

//objCType 要求傳入用於描述數據的類型、大小的字符串,使用@encode 指令包裝數據所屬的類型。

 

NSMutableArray *mArray=[NSMutableArray arrayWithCapacity: 3];

[mArray addObject: v];

NSRect rect2;

[[mArray objectAtIndex: 0] getValue: &rect2];

//NSValue 的-(void) getValue: (void*) value 方法可以將NSValue 中的數據內容取出,要求傳入的參數是一個指針,也就是說getValue 方法將你傳入的指針指向存儲的數據。

//一般Cocoa 中的getXXX 方法都是這個作用,這也是爲什麼前面的getter 方法不要以get作爲方法前綴的原因。

對於基本數據類型,你可以使用簡便的NSNumber 來封裝,它是NSValue 的子類。

如果你想存儲空值到集合類,可以使用NSNull,它使用NSNull *n =[NSNull null];的方式創建。

 

30日期類型

Cocoa 中使用NSDate 類型表示日期。

 

31數據緩衝區(其實就是java中的字節數組)

Cocoa 中使用NSData 類型來實現緩衝區,用於存儲二進制的數據類型,譬如:從網絡下載回來的文件等。

NSData 是長度不可變的數據緩衝區,還有一個NSMutableData 用來存儲長度可變的數據緩衝區。

 

32寫入和讀取屬性(簡直就是java序列化和反序列化的翻版)

在iPhone 的*.ipa 文件中,你經常可以看到*.plist 文件,它保存了程序的相關屬性,叫做屬性列表。其實它就是NSArray、NSDictionary、NSString、NSData 持久化之後的文件。

這幾個類型都有一個成員方法writeToFile: (NSString*) file atomically: BOOL 用於將自己寫入到一個文件。atomically 爲YES 表示文件先存儲到臨時文件區,如果文件保存成功,再替換掉原始文件,這樣的好處是可以防止在保存文件過程中出錯,但是僅適用於小文件,因爲你相當於是在臨時文件存儲區也放了一份,再加上原始文件,就是兩份文件,如果文件比較大,將會佔用較多的用戶的磁盤空間。

如果你要持久化的類型不是上述的數組、字典、緩衝區,那該怎麼辦呢?Objective-C 中也有和JAVA 一樣的序列化、反序列化支持,使用NSCoding 協議。NSCoding 協議定義瞭如下兩個方法:

-(void) encodeWithCoder: (NSCoder*) coder;

-(id) initWithCoder: (NSCoder*) decoder;

第一個方法相當於編碼對象,第二個方法是解碼回對象,也就相當於給類型定義了一個新的init 方法而已。

 

33對象的複製

對象的複製就相當於JAVA 中的clone()方法,也就是對象的深度複製,所謂深度複製就是重新分配一個存儲空間,並將原對象的內容都複製過來,從這些描述可以看出,複製也會分配空間,那就是你要對複製出來的對象release,就是前面所說的alloc、new、copy 操作創建的對象,要手工release。

Objective-C 中的一個對象是否可以被複制,要看它的類型是否遵循NSCopying 協議,這個協議中有個複製方法-(id) copyWithZone: (*NSZone) zone 需要我們去實現。

 

34多線程

Objective-C 的多線程編程與JAVA 語言極其類似分爲原始的線程操作、線程池兩種,後者其實就是使用隊列等機制對前者的封裝。JAVA 也一樣,原始的線程操作使用Thread 類,線程池的操作使用java.util.concurrent.*中的類庫。

Objective-C 中NSThread 類型表示線程NSCondition 用於執行同步操作,在功能和用法上相當於JAVA 中的java.util.concurrent.*包中的Lock 對象。

另外,Objective-C 也支持@synchronized 指令做代碼同步,寫法也和JAVA 中的很相似。

@synchronized(要加鎖的對象){

//同步執行的代碼

}

 

另外比較有趣的是,如果你想更新UI 上的某一個部件,就需要在發起的新線程裏調用UI 所在的主線程上的一個方法,新線程不能直接訪問主線程的方法,需要在run 方法中使用如下的方法:

- (void) performSelectorOnMainThread: (SEL) aSelector withObject: (id) arg waitUntilDone: (BOOL) wait

如果你對javaswing熟悉的話,你應該知道在UI界,大多數更新界面的都必須在一個單線程中執行,因爲如果更新界面是多線程的話會很難處理的,java swing處理的方法是更新界面的代碼放在專門更新UI的線程下執行,其實這裏IOS也是這麼一個思想。

 

Objective-C 使用NSOperation、NSOperationQueue 兩個類型實現線程池的操作,NSOpertion就好比JAVA 中的Runnable,其中的main(名字有點兒奇怪)方法也就是你要執行的操作,NSOperationQueue 是一個線程池隊列,你只需要把NSOperation 添加到NSOperationQueue,隊列就會retain 你的NSOperation,然後執行其中的操作,直到執行完畢。隊列中會有多個操作,隊列會按照你添加的順序逐個執行,也就說隊列中的任務是串行的。

java一樣,如果線程池可以滿足你的業務需求,儘量使用線程池,而不是原始的NSThread,因爲使用線程池屏蔽了許多線程自身需要處理的問題,代碼也更加簡潔。

 

35KVC 與KVO(這個話題真高級)

KVC 是NSKeyValueCoding 的縮寫,它是Foundation Kit 中的一個NSObject 的Category,作用你可以類比JAVA 中的反射機制,就是動態訪問一個對象中的屬性。

KVC 在解析key 的字符串的時候,是會比你正常調用setter、getter 要慢的,而且編譯器無法在編譯器對你的方法調用做出檢查(因爲你的屬性名都是字符串,只有運行時纔會知道你有沒有寫錯),出錯的機率也會提高,所以請不要隨意使用KVC,而省去setter、getter 方法。KVC 一般用於動態綁定,也就是運行時才能確定誰調用哪個方法,編譯期並不確定。

KVO就是NSKeyValueObserving的縮寫,它也是Foundation Kit中的一個NSObject的Category,KVO 基於KVC 實現,基於觀察者設計模式(Observer Pattern)實現的一種通知機制,你可以類比JAVA 中的JMS,通過訂閱的方式,實現了兩個對象之間的解耦,但又可以讓他們相互調用。(具體請查資料)

 

36謂詞NSPredicate

Cocoa 提供了NSPredicate 用於指定過濾條件,謂詞是指在計算機中表示計算真假值的函數,它使用起來有點兒像SQL 的查詢條件,主要用於從集合中分揀出符合條件的對象,也可以用於字符串的正則匹配

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章