Objective-C 的隐藏特性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/211616/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hidden features of Objective-C
提问by Clokey
Objective-C is getting wider use due to its use by Apple for Mac OS X and iPhone development. What are some of your favourite "hidden" features of the Objective-C language?
由于 Apple 将 Objective-C 用于 Mac OS X 和 iPhone 开发,它得到了更广泛的使用。你最喜欢的 Objective-C 语言的一些“隐藏”特性是什么?
- One feature per answer.
- Give an example and short description of the feature, not just a link to documentation.
- Label the feature using a title as the first line.
- 每个答案一个功能。
- 给出该功能的示例和简短描述,而不仅仅是文档的链接。
- 使用标题作为第一行标记要素。
回答by benzado
Method Swizzling
方法调配
Basically, at runtime you can swap out one implementation of a method with another.
基本上,在运行时,您可以将一个方法的一个实现替换为另一个。
Here is a an explanation with code.
One clever use case is for lazy loading of a shared resource: usually you would implement a sharedFoomethod by acquiring a lock, creating the fooif needed, getting its address, releasing the lock, then returning the foo. This ensures that the foois only created once, but every subsequent access wastes time with a lock that isn't needed any more.
一个聪明的用例是共享资源的延迟加载:通常你会sharedFoo通过获取一个锁,创建foo如果需要,获取它的地址,释放锁,然后返回一个方法来实现一个方法foo。这确保foo只创建一次,但每次后续访问都会浪费时间使用不再需要的锁。
With method swizzling, you can do the same as before, except once the foohas been created, use swizzling to swap out the initial implementation of sharedFoowith a second one that does no checks and simply returns the foothat we now know has been created!
使用方法 swizzling,您可以执行与以前相同的操作,除了foo在创建之后,使用 swizzling 将 的初始实现sharedFoo替换为第二个不进行检查并仅返回foo我们现在知道已创建的 !
Of course, method swizzling can get you into trouble, and there may be situations where the above example is a bad idea, but hey... that's why it's a hiddenfeature.
当然,方法 swizzling 可能会给您带来麻烦,并且在某些情况下,上面的示例可能是个坏主意,但是嘿...这就是为什么它是隐藏功能的原因。
回答by splattne
Posing
摆姿势
Objective-C permits a class to entirely replace another classwithin an application. The replacing class is said to "pose as" the target class. All messages sent to the target class are then instead received by the posing class. There are some restrictions on which classes can pose:
Objective-C 允许一个类完全替换应用程序中的另一个类。替换类被称为“构成”目标类。然后,发送到目标类的所有消息都由冒充类接收。哪些类可以构成有一些限制:
- A class may only pose as one of its direct or indirect superclasses
- The posing class must not define any new instance variables which are absent from the target class (though it may define or override methods).
- No messages must have been sent to the target class prior to the posing.
- 一个类只能作为其直接或间接超类之一
- 伪装类不能定义目标类中不存在的任何新实例变量(尽管它可以定义或覆盖方法)。
- 在冒充之前,不得向目标类发送任何消息。
Posing, similarly to categories, allows globally augmenting existing classes. Posing permits two features absent from categories:
姿势,类似于类别,允许全局增加现有的类。姿势允许类别中不存在的两个特征:
- A posing class can call overridden methods through super, thus incorporating the implementation of the target class.
- A posing class can override methods defined in categories.
- 一个伪装类可以通过 super 调用被覆盖的方法,从而合并目标类的实现。
- 伪装类可以覆盖类别中定义的方法。
An example:
一个例子:
@interface CustomNSApplication : NSApplication
@end
@implementation CustomNSApplication
- (void) setMainMenu: (NSMenu*) menu
{
// do something with menu
}
@end
class_poseAs ([CustomNSApplication class], [NSApplication class]);
This intercepts every invocation of setMainMenu to NSApplication.
这会拦截每次对 NSApplication 的 setMainMenu 调用。
回答by pfeilbr
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.
当一个对象被发送一条没有方法的消息时,运行时系统会给它另一个机会在放弃之前处理调用。如果对象支持 -forward:: 方法,则运行时调用此方法,将有关未处理调用的信息传递给它。转发调用的返回值被传播回方法的原始调用者。
-(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
来自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.
这是非常强大的,在 Ruby 社区中大量用于各种 DSL 和 Rails 等。起源于 Smalltalk,它影响了 Objective-C 和 Ruby。
回答by Brent Royal-Gordon
ISA Switching
ISA交换
Need to override all of an object's behaviors? You can actually change the class of an active object with a single line of code:
需要覆盖对象的所有行为吗?您实际上可以使用一行代码更改活动对象的类:
obj->isa = [NewClass class];
This only changes the class that receives method calls for that object; it doesn't change the object's layout in memory. Thus, this is only really useful when you have a set of classes with the same ivars (or one with a subset of the others') and you want to switch between them.
这只会更改接收该对象的方法调用的类;它不会改变对象在内存中的布局。因此,这仅在您有一组具有相同 ivar(或具有其他子集的类)并且您想在它们之间切换时才真正有用。
One piece of code I've written uses this for lazy loading: it allocates an object of class A, fills a couple critical ivars (in this case, mainly a record number) and switches the isapointer to point to LazyA. When any method other than a very small set like releaseand retainis called, LazyAloads all the data from disk, finishes filling in the ivars, switches the isapointer back to A, and forwards the call to the real class.
我写的一段代码将它用于延迟加载:它分配一个 class 对象A,填充几个关键变量(在这种情况下,主要是一个记录号)并将isa指针切换到指向LazyA. 当比一个非常小的一组像其他任何方法release和retain被调用,LazyA负载从磁盘中的所有数据,完成填补了高德,切换isa指针回A,并调用转发给真正的类。
回答by schwa
#include <Foundation/Debug.h>
Lots of tools for trying to track down memory leaks, premature deallocs, and more in that header file.
许多工具可用于尝试在该头文件中跟踪内存泄漏、过早释放等。
回答by Marco
Categories
类别
Using Categories, you can add methods to built-in classes without subclassing. Full reference.
使用类别,您可以向内置类添加方法而无需子类化。完整参考。
It's nice to add convenience methods to commonly used classes, such as NSString or NSData.
为常用类添加便利方法是很好的,例如 NSString 或 NSData。
回答by Michael Ledford
Objective-C Runtime Reference
Objective-C 运行时参考
It's easy to forget that the syntactic sugar of Objective-C is converted to normal C function calls that are the Object-C Runtime. It's likely that you will never need to actually delve into and use anything in the runtime. That is why I would consider this a 'hidden feature'.
很容易忘记,Objective-C 的语法糖被转换为普通的 C 函数调用,即 Object-C 运行时。您可能永远不需要在运行时真正深入研究和使用任何东西。这就是为什么我会认为这是一个“隐藏功能”。
Let me give a way one might use the runtime system.
让我给出一种可能使用运行时系统的方法。
Let's say that someone is designing an external framework API that will be used by third parties. And that someone designs a class in the framework that abstractly represents a packet of data, we'll call it MLAbstractDataPacket. Now it's up to the application who is linking in the framework to subclass MLAbstractDataPacketand define the subclass data packets. Every subclass must override the method +(BOOL)isMyKindOfDataPacket:(NSData *)data.
假设有人正在设计将由第三方使用的外部框架 API。并且有人在框架中设计了一个抽象表示数据包的类,我们称之为MLAbstractDataPacket。现在由在框架中链接到子类MLAbstractDataPacket并定义子类数据包的应用程序来决定。每个子类都必须覆盖该方法+(BOOL)isMyKindOfDataPacket:(NSData *)data。
With that information in mind...
考虑到这些信息......
It would be nice if MLAbstractDataPacketprovided a convenience method that returned the correct initialized class for a packet of data that comes in the form +(id)initWithDataPacket:(NSData *)data.
如果MLAbstractDataPacket提供一个方便的方法来为表单中的数据包返回正确的初始化类,那就太好了+(id)initWithDataPacket:(NSData *)data。
There's only one problem here. The superclass doesn't know about any of its subclasses. So here you could use the runtime method objc_getClassList()along with objc_getSuperclass()to find the classes that are subclasses of MLAbstractDataPacket. Once you have a list of subclasses you can then try +isMyKindOfDataPacket:on each until one is found or not found.
这里只有一个问题。超类不知道它的任何子类。所以在这里,你可以使用运行时方法objc_getClassList()以及objc_getSuperclass()发现是MLAbstractDataPacket的子类。一旦你有一个子类列表,你就可以尝试+isMyKindOfDataPacket:每个子类,直到找到或找不到。
The reference information about this can be found at http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html.
有关这方面的参考信息可以在http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html 中找到。
回答by Kris
I like the verbose method naming like [myArray writeToFile:myPath atomically:YES], where every argument has a label.
我喜欢冗长的方法命名 like [myArray writeToFile:myPath atomically:YES],其中每个参数都有一个标签。

