由于 Apple 将 Objective-C 用于 Mac OS X 和 iPhone 开发,Objective-C 的使用越来越广泛。您最喜欢 Objective-C 语言的哪些“隐藏”特性?
- 每个答案一个功能。
- 给出该功能的示例和简短描述,而不仅仅是文档链接。
- 使用标题作为第一行标记要素。
由于 Apple 将 Objective-C 用于 Mac OS X 和 iPhone 开发,Objective-C 的使用越来越广泛。您最喜欢 Objective-C 语言的哪些“隐藏”特性?
基本上,在运行时,您可以将一种方法的一种实现换成另一种。
一个聪明的用例是共享资源的延迟加载:通常你会sharedFoo
通过获取一个锁来实现一个方法,foo
如果需要的话,创建它的地址,释放锁,然后返回foo
. 这确保了foo
只创建一次,但每次后续访问都会浪费时间使用不再需要的锁。
使用方法 swizzling,您可以像以前一样做,除了一旦foo
创建,使用 swizzling 将初始实现换成sharedFoo
第二个不检查并简单地返回foo
我们现在知道已经创建的实现!
当然,method swizzling 会给你带来麻烦,并且在某些情况下上面的例子不是一个好主意,但是嘿......这就是为什么它是一个隐藏的特性。
Objective-C 允许一个类完全替换应用程序中的另一个类。替换类被称为“冒充”目标类。然后,发送到目标类的所有消息都由 POS 类接收。对哪些类可以构成一些限制:
与类别类似,Posing 允许全局扩充现有类别。姿势允许类别中缺少的两个特征:
一个例子:
@interface CustomNSApplication : NSApplication
@end
@implementation CustomNSApplication
- (void) setMainMenu: (NSMenu*) menu
{
// do something with menu
}
@end
class_poseAs ([CustomNSApplication class], [NSApplication class]);
这会拦截对 NSApplication 的每次 setMainMenu 调用。
Object Forwarding/Method Missing
When an object is sent a message for which it has no method, the runtime system gives it another chance to handle the call before giving up. If the object supports a -forward:: method, the runtime calls this method, passing it information about the unhandled call. The return value from the forwarded call is propagated back to the original caller of the method.
-(retval_t)forward:(SEL)sel :(arglist_t)args {
if ([myDelegate respondsTo:sel])
return [myDelegate performv:sel :args]
else
return [super forward:sel :args];
}
Content from Objective-C Pocket Reference
This is very powerful and is used heavily in the Ruby community for the various DSLs and rails, etc. Originated in Smalltalk which influenced both Objective-C and Ruby.
需要覆盖对象的所有行为?您实际上可以使用一行代码更改活动对象的类:
obj->isa = [NewClass class];
这只会更改接收该对象的方法调用的类;它不会改变对象在内存中的布局。因此,只有当您有一组具有相同 ivars 的类(或一个具有其他类的子集)并且您想在它们之间切换时,这才真正有用。
我编写的一段代码使用它进行延迟加载:它分配一个 class 对象A
,填充几个关键 ivars(在这种情况下,主要是记录号)并将isa
指针切换到指向LazyA
. 当调用除了非常小的集合之外的任何方法时release
,从磁盘加载所有数据,完成 ivars 的填充,将指针切换回,并将调用转发到真实类。retain
LazyA
isa
A
#include <Foundation/Debug.h>
许多工具用于尝试在该头文件中追踪内存泄漏、过早解除分配等。
Objective-C 运行时参考
很容易忘记,Objective-C 的语法糖被转换为普通的 C 函数调用,即 Object-C 运行时。您可能永远不需要在运行时中真正深入研究和使用任何东西。这就是为什么我会认为这是一个“隐藏的功能”。
让我给出一种使用运行时系统的方法。
假设有人正在设计一个将由第三方使用的外部框架 API。并且有人在框架中设计了一个抽象表示数据包的类,我们称之为MLAbstractDataPacket
。现在由在框架中链接的应用程序来子类MLAbstractDataPacket
化和定义子类数据包。每个子类都必须重写该方法+(BOOL)isMyKindOfDataPacket:(NSData *)data
。
考虑到这些信息...
如果MLAbstractDataPacket
提供一个方便的方法,该方法为以 . 形式出现的数据包返回正确的初始化类,那就太好了+(id)initWithDataPacket:(NSData *)data
。
这里只有一个问题。超类不知道它的任何子类。因此,您可以在这里使用运行时方法objc_getClassList()
来objc_getSuperclass()
查找作为 MLAbstractDataPacket 子类的类。一旦你有了一个子类列表,你就可以尝试+isMyKindOfDataPacket:
每个子类,直到找到或找不到一个。
有关此的参考信息可以在http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html找到。
我喜欢详细的方法命名如[myArray writeToFile:myPath atomically:YES]
,其中每个参数都有一个标签。