從 C++ 到 Objective-C:STL 和 Cocoa


C++ 標准庫是其強大的一個原因。即使它還有一些不足,但是已經能夠算作是比較完備的了。這並不是語言的一部分,而是屬於一種擴展,其他語言也有類似的部分。在 Objective-C 中,你不得不在 Cocoa 里面尋找容器、遍歷器或者其他一些真正可以使用的算法。

容器

Cocoa 的容器比 C++ 更加面向對象,它不使用模板實現,只能存放對象。現在可用的容器有:

  • NSArray 和 NSMutableArray:有序集合;
  • NSSet 和 NSMutableSet:無序集合;
  • NSDictionary 和 NSMutableDictionary:鍵值對形式的關聯集合;
  • NSHashTable:使用弱引用的散列表(Objective-C 2.0 新增)。

你可能會發現這其中並沒有 NSList 或者 NSQueue。事實上,這些容器都可以由 NSArray 實現。

不同於 C++ 的 vector<T>,Objective-C 的 NSArray 真正隱藏了它的內部實現,僅能夠使用訪問器獲取其內容。因此,NSArray 沒有義務為內存單元優化其內容。NSArray 的實現有一些妥協,以便 NSArray 能夠像數組或者列表一樣使用。既然 Objective-C 的容器只能存放指針,單元維護就會比較有效率了。

NSHashTable 等價於 NSSet,但它使用的是弱引用(我們曾在前面的章節中講到過)。這對於垃圾收集器很有幫助。

遍歷器

經典的枚舉

純面向對象的實現讓 Objective-C 比 C++ 更容易實現遍歷器。NSEnumerator 就是為了這個設計的:

NSArray* array = [NSArray arrayWithObjects:object1, object2, object3, nil];
NSEnumerator* enumerator = [array objectEnumerator]
NSString* aString = @"foo"
id anObject = [enumerator nextObject];
while (anObject != nil) 
{ 
    [anObject doSomethingWithString:aString]
    anObject = [enumerator nextObject]
}

容器的 objectEnumerator 方法返回一個遍歷器。遍歷器可以使用 nextObject 移動自己。這種行為更像 Java 而不是 C++。當遍歷器到達容器末尾時,nextObject 返回 nil。下面是最普通的使用遍歷器的語法,使用的 C 語言風格的簡寫:

NSArray* array = [NSArray arrayWithObjects:object1, object2, object3, nil];
NSEnumerator* enumerator = [array objectEnumerator]
NSString* aString = @"foo"
id anObject = nil
while ((anObject = [enumerator nextObject])) 
{ 
    [anObject doSomethingWithString:aString]
} // 雙括號能夠防止 gcc 發出警告

快速枚舉

Objective-C 2.0 提供了一個使用遍歷器的新語法,隱式使用 NSEnumerator(其實和一般的 NSEnumerator 沒有什么區別)。它的具體形式是:

NSArray* someContainer = ...; 
for(id object in someContainer) { 
// 每一個對象都是用 id 類型 ... } 
for(NSString* object in someContainer) 
{ // 每一個對象都是 NSString ...
// 開發人員需要處理不是 NSString* 的情況 
}

函數對象

使用選擇器

Objective-C 的選擇器很強大,因而大大減少了函數對象的使用。事實上,弱類型允許用戶無需關心實際類型就可以發送消息。例如,下面的代碼同前面使用遍歷器的是等價的:

NSArray* array = [NSArray arrayWithObjects:object1, object2, object3, nil]
NSString*aString = @"foo"
[array makeObjectsPerformSelector:@selector(doSomethingWithString:)withObject:aString];

在這段代碼中,每個對象不一定非得是 NSString 類型,並且對象也不需要必須實現了 doSomethingWithString: 方法(這會引發一個異常:selector not recognized)。

IMP 緩存

我們在這里不會詳細解釋這個問題,但是的確可以獲得 C 函數的內存地址。通過僅查找一次函數地址,可以優化同一個選擇器的多次調用。這被稱為 IMP 緩存,因為 Objective-C 用於方法實現的數據類型就是 IMP。

調用 class_getMethodImplementation() 就可以獲得這么一個指針。但是請注意,這是指向實現方法的真實的指針,因此不能有虛調用。它的使用一般在需要很好的時間優化的場合,並且必須非常小心。

算法

STL 中那一大堆通用算法在 Objective-C 中都沒有對等的實現。相反,你應該仔細查找下各個容器中有沒有你需要的算法。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com