从 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 中都没有对等的实现。相反,你应该仔细查找下各个容器中有没有你需要的算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值