Objective-C的隐藏功能

时间:2008-10-17 10:06:22

标签: iphone objective-c macos hidden-features

由于Apple用于Mac OS X和iPhone开发,Objective-C正在得到更广泛的应用。您最喜欢Objective-C语言的一些“隐藏”功能是什么?

  • 每个答案都有一个功能。
  • 举例说明该功能,而不仅仅是文档链接。
  • 使用标题作为第一行标记要素。

8 个答案:

答案 0 :(得分:20)

方法调整

基本上,在运行时,您可以将方法的一个实现换成另一个。

Here is a an explanation with code.

一个聪明的用例是延迟加载共享资源:通常你会通过获取锁来实现sharedFoo方法,如果需要创建foo,获取其地址,释放锁,然后返回foo。这可确保foo仅创建一次,但每次后续访问都会浪费时间,而不再需要锁定。

使用方法调配,你可以像以前一样做,除非创建foo后,使用swizzling将sharedFoo的初始实现替换为不进行检查的第二个实现{只需返回我们现在知道已创建的foo

当然,方法调整会让你陷入困境,并且可能会出现上述示例不好的情况,但是嘿......这就是为什么它是隐藏功能。

答案 1 :(得分:16)

Objective-C允许类在应用程序中完全替换另一个类。替换类被称为“伪装成”目标类。然后,冒充类接收发送到目标类的所有消息。哪些类可以构成一些限制:

  • 一个类只能构成其直接或间接超类之一
  • 冒充类不得定义目标类中不存在的任何新实例变量(尽管它可以定义或覆盖方法)。
  • 在冒充之前,不得向目标类发送任何消息。

与类别类似,Posing允许全局扩充现有类。构成允许类别中缺少两个特征:

  • 冒充类可以通过super调用重写方法,从而合并目标类的实现。
  • 冒充类可以覆盖类别中定义的方法。

示例:

@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)

ISA切换

需要覆盖所有对象的行为吗?实际上,您可以使用一行代码更改活动对象的类:

obj->isa = [NewClass class];

这只会更改接收该对象的方法调用的类;它不会更改内存中对象的布局。因此,只有当您拥有一组具有相同ivars的类(或其他具有其他子集的类)并且您希望在它们之间切换时,这才真正有用。

我编写的一段代码使用它来进行延迟加载:它分配一个类A的对象,填充几个关键的ivars(在这种情况下,主要是一个记录号)并切换{{1指向isa的指针。当调用除LazyArelease之类的非常小的集合之外的任何方法时,retain将从磁盘加载所有数据,完成填充ivars,切换LazyA指针回到isa,然后将呼叫转发给真正的班级。

答案 4 :(得分:10)

#include <Foundation/Debug.h>

许多用于尝试在该头文件中跟踪内存泄漏,过早deallocs等的工具。

答案 5 :(得分:10)

<强>分类

使用Categories,您可以在不进行子类化的情况下将方法添加到内置类中。 Full reference

为常用类添加便捷方法很好,例如NSString或NSData。

答案 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]命名的详细方法,其中每个参数都有一个标签。