12

由于 Apple 将 Objective-C 用于 Mac OS X 和 iPhone 开发,Objective-C 的使用越来越广泛。您最喜欢 Objective-C 语言的哪些“隐藏”特性?

  • 每个答案一个功能。
  • 给出该功能的示例和简短描述,而不仅仅是文档链接。
  • 使用标题作为第一行标记要素。
4

8 回答 8

20

方法混搭

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

这是一个带代码的解释。

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

使用方法 swizzling,您可以像以前一样做,除了一旦foo创建,使用 swizzling 将初始实现换成sharedFoo第二个不检查并简单地返回foo我们现在知道已经创建的实现!

当然,method swizzling 会给你带来麻烦,并且在某些情况下上面的例子不是一个好主意,但是嘿......这就是为什么它是一个隐藏的特性。

于 2008-10-18T05:23:30.930 回答
16

摆姿势

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

  • 一个类只能作为其直接或间接超类之一
  • 姿势类不得定义目标类中不存在的任何新实例变量(尽管它可以定义或覆盖方法)。
  • 在摆姿势之前,必须没有向目标类发送任何消息。

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

  • 一个pose类可以通过super调用被覆盖的方法,从而合并目标类的实现。
  • 姿势类可以覆盖类别中定义的方法。

一个例子:

@interface CustomNSApplication : NSApplication
@end

@implementation CustomNSApplication
- (void) setMainMenu: (NSMenu*) menu
{
     // do something with menu
}
@end

class_poseAs ([CustomNSApplication class], [NSApplication class]);

这会拦截对 NSApplication 的每次 setMainMenu 调用。

于 2008-10-17T10:37:18.757 回答
15

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.

于 2008-10-18T02:45:43.543 回答
11

ISA交换

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

obj->isa = [NewClass class];

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

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

于 2009-03-25T01:11:39.653 回答
10
#include <Foundation/Debug.h>

许多工具用于尝试在该头文件中追踪内存泄漏、过早解除分配等。

于 2008-10-17T15:39:05.650 回答
10

类别

使用类别,您可以将方法添加到内置类而无需子类化。完整参考

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

于 2008-10-22T20:15:07.493 回答
4

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找到。

于 2008-10-18T07:24:28.067 回答
0

我喜欢详细的方法命名如[myArray writeToFile:myPath atomically:YES],其中每个参数都有一个标签。

于 2008-10-22T20:23:43.407 回答