【发布时间】:2010-09-17 17:14:09
【问题描述】:
Objective-C 被 Apple 用于 Mac OS X 和 iPhone 开发的用途越来越广泛。您最喜欢 Objective-C 语言的哪些“隐藏”特性?
- 每个答案一个功能。
- 提供功能示例和简短说明,而不仅仅是文档链接。
- 使用标题作为第一行标记功能。
【问题讨论】:
标签: iphone objective-c macos hidden-features
Objective-C 被 Apple 用于 Mac OS X 和 iPhone 开发的用途越来越广泛。您最喜欢 Objective-C 语言的哪些“隐藏”特性?
【问题讨论】:
标签: iphone objective-c macos hidden-features
基本上,在运行时,您可以将一种方法的一种实现换成另一种。
Here is a an explanation with code.
一个聪明的用例是共享资源的延迟加载:通常你会通过获取一个锁来实现sharedFoo方法,如果需要,创建foo,获取它的地址,释放锁,然后返回@ 987654324@。这样可以确保 foo 只创建一次,但每次后续访问都会浪费时间使用不再需要的锁。
使用方法 swizzling,您可以像以前一样做,除了一旦创建了 foo,使用 swizzling 将 sharedFoo 的初始实现换成第二个不检查并简单地返回 @我们现在知道的 987654328@ 已经创建!
当然,方法调配可能会给您带来麻烦,并且在某些情况下,上面的示例可能不是一个好主意,但是嘿...这就是为什么它是一个隐藏功能。
【讨论】:
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 调用。
【讨论】:
对象转发/方法丢失
当一个对象被发送一个它没有的消息时 方法,运行时系统给了它另一个处理的机会 放弃前的电话。如果对象支持 -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 等。起源于影响 Objective-C 和 Ruby 的 Smalltalk。
【讨论】:
-[Object forward::] 已被弃用很久,并且在现代 Objective-C 运行时不再可用。如 iOS 设备上的 64 位和 ARM。
需要覆盖对象的所有行为?您实际上可以通过一行代码更改活动对象的类:
obj->isa = [NewClass class];
这只会更改接收该对象的方法调用的类;它不会改变对象在内存中的布局。因此,只有当您有一组具有相同 ivars(或一个具有其他 ivars 的子集)的类并且您想在它们之间切换时,这才真正有用。
我编写的一段代码使用它进行延迟加载:它分配一个 A 类的对象,填充几个关键 ivars(在本例中,主要是记录号)并将 isa 指针切换到指向LazyA。当调用除了像release 和retain 这样非常小的集合之外的任何方法时,LazyA 从磁盘加载所有数据,完成对 ivars 的填充,将isa 指针切换回A,然后转发调用真正的类。
【讨论】:
Instance variable 'isa' is protected. 有没有办法解决这个问题?见stackoverflow.com/questions/8512793/…
#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] 这样的详细方法命名,其中每个参数都有一个标签。
【讨论】: