由于Apple用于Mac OS X和iPhone开发,Objective-C正在得到更广泛的应用。您最喜欢Objective-C语言的一些“隐藏”功能是什么?
答案 0 :(得分:20)
基本上,在运行时,您可以将方法的一个实现换成另一个。
Here is a an explanation with code.
一个聪明的用例是延迟加载共享资源:通常你会通过获取锁来实现sharedFoo
方法,如果需要创建foo
,获取其地址,释放锁,然后返回foo
。这可确保foo
仅创建一次,但每次后续访问都会浪费时间,而不再需要锁定。
使用方法调配,你可以像以前一样做,除非创建foo
后,使用swizzling将sharedFoo
的初始实现替换为不进行检查的第二个实现{只需返回我们现在知道已创建的foo
!
当然,方法调整会让你陷入困境,并且可能会出现上述示例不好的情况,但是嘿......这就是为什么它是隐藏功能。
答案 1 :(得分:16)
Objective-C允许类在应用程序中完全替换另一个类。替换类被称为“伪装成”目标类。然后,冒充类接收发送到目标类的所有消息。哪些类可以构成一些限制:
与类别类似,Posing允许全局扩充现有类。构成允许类别中缺少两个特征:
示例:
@interface CustomNSApplication : NSApplication
@end
@implementation CustomNSApplication
- (void) setMainMenu: (NSMenu*) menu
{
// do something with menu
}
@end
class_poseAs ([CustomNSApplication class], [NSApplication class]);
这会拦截setMainMenu到NSApplication的每次调用。
答案 2 :(得分:15)
对象转发/方法缺失
当一个对象被发送一个它没有的消息时 方法,运行时系统给它另一个处理的机会 放弃之前的电话。如果对象支持a -forward ::方法,运行时调用此方法,传递它 有关未处理呼叫的信息。来自的返回值 转发的呼叫将传播回原来的呼叫者 方法。
-(retval_t)forward:(SEL)sel :(arglist_t)args {
if ([myDelegate respondsTo:sel])
return [myDelegate performv:sel :args]
else
return [super forward:sel :args];
}
来自Objective-C Pocket Reference的内容
这是非常强大的,并且在Ruby社区中大量用于各种DSL和rails等。起源于Smalltalk,它影响了Objective-C和Ruby。
答案 3 :(得分:11)
需要覆盖所有对象的行为吗?实际上,您可以使用一行代码更改活动对象的类:
obj->isa = [NewClass class];
这只会更改接收该对象的方法调用的类;它不会更改内存中对象的布局。因此,只有当您拥有一组具有相同ivars的类(或其他具有其他子集的类)并且您希望在它们之间切换时,这才真正有用。
我编写的一段代码使用它来进行延迟加载:它分配一个类A
的对象,填充几个关键的ivars(在这种情况下,主要是一个记录号)并切换{{1指向isa
的指针。当调用除LazyA
和release
之类的非常小的集合之外的任何方法时,retain
将从磁盘加载所有数据,完成填充ivars,切换LazyA
指针回到isa
,然后将呼叫转发给真正的班级。
答案 4 :(得分:10)
#include <Foundation/Debug.h>
许多用于尝试在该头文件中跟踪内存泄漏,过早deallocs等的工具。
答案 5 :(得分:10)
答案 6 :(得分:4)
Objective-C运行时参考
很容易忘记将Objective-C的语法糖转换为Object-C Runtime的正常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找到。
答案 7 :(得分:0)
我喜欢用[myArray writeToFile:myPath atomically:YES]
命名的详细方法,其中每个参数都有一个标签。