Message Forwarding
来源:互联网 发布:新浪微博域名二次修改 编辑:程序博客网 时间:2024/05/16 09:44
Message Forwarding
Objective-C object messaging finds and executes a method on an object based on the message it receives. The object type can either be specified in the code and statically bound at compile time (static typing) or be unspecified with its type resolved at runtime (dynamic typing). In either case, at runtime, the receiving object interprets the message to determine which method to invoke. This runtime resolution of method calls makes it easy to change and/or extend programs dynamically, but also carries with it a certain risk: it permits a program to send a message to an object that may not have a corresponding method attached to it. Under the default scenario, if this happens, a runtime exception is thrown. However, Objective-C provides another option: through a mechanism called message forwarding, it is possible to configure an object to perform user-defined processing when it receives a message not mapped to its set of methods. Message forwarding enables an object to perform a variety of logic on any unrecognized message it receives, perhaps parceling it out to a different receiver who can respond to the message, sending any unrecognized messages to the same destination, or simply silently “swallowing” the message (i.e., performing no processing nor causing a runtime error to be thrown).
Forwarding Options
Objective-C provides two types of message forwarding options that you can use.
- Fast forwarding: Classes that descend fromNSObject can implement fast forwarding by overriding the NSObject forwardingTargetForSelector: method to forward the method to another object. This technique makes it appear like the implementations of your object and the forwarding object are combined. This simulates the behavior of multiple inheritance of class implementations. It works well if you have a target class that defines all the possible messages that your object can consume.
- Normal (full) forwarding: Classes that descend from NSObject can implement normal forwarding by overriding the NSObject forwardInvocation: method. This technique enables your object to use the full contents of the message (target, method name, parameters).
Fast forwarding works well if you have a target class that defines all the possible messages that your object can consume. Full fowarding should be used if you don’t have such a target class or you would like to perform other processing on message receipt (for example, just logging and swallowing the message).
Message Forwarding Helper Class
First, you’ll create the helper class. In Xcode, create a new Objective-C class. Name it HydrogenHelper and make the Elements project its target. In the Xcode navigator pane, observe that two new files (HydrogenHelper.h andHydrogenHelper.m) have been created. Select theHydrogenHelper.h file, and then in the editor pane, update the interface as shown in Listing 3-9.
Listing 3-9. HydrogenHelper Interface
#import <Foundation/Foundation.h>@interface HydrogenHelper : NSObject- (NSString *) factoid;@end
This interface declares a single instance method, factoid, which returns a pointer to an NSString (NSString *). Next, select the implementation file (HydrogenHelper.m) and define the factoid method as shown in Listing 3-10.
Listing 3-10. HydrogenHelper Implementation
#import "HydrogenHelper.h"@implementation HydrogenHelper- (NSString *) factoid{ return @"The lightest element and most abundant chemical substance.";}
As you can see from Listing 3-10, the HydrogenHelper factoid method returns a simple fact about the Hydrogen element. Now you are going to update the Hydrogen class to support fast forwarding. In the Hydrogen implementation (Hydrogen.m), add the following code to overwrite the default implementation of the forwardingTargetForSelector:method, as shown in Listing 3-11 (updates are shown in bold).
Listing 3-11. Hydrogen Class Message Fast Forwarding Updates
@implementation Hydrogen{@private HydrogenHelper *helper;}...- (id) initWithNeutrons:(NSUInteger)neutrons{ if ((self = [super init])) { // Initialization code here. _chemicalElement = @"Hydrogen"; _atomicSymbol = @"H"; _protons = 1; _neutrons = neutrons; // Create helper for message forwarding helper = [[HydrogenHelper alloc] init]; } return self;}- (id) forwardingTargetForSelector:(SEL)aSelector{ if ([helper respondsToSelector:aSelector]) { return helper; } return nil;}...@end
First, the Hydrogen class adds a HydrogenHelper* instance variable. Next, in the init method, the HydrogenHelper object is created and initialized. This is the target object that will be used for message forwarding. Finally, theforwardingTargetForSelector: method is implemented. The method first checks to see if the message is one that the target (HydrogenHelper) object can process. If it can, it returns that object; otherwise, it returns nil. Recall that theHydrogenHelper class has a single instance method, factoid. Thus if a Hydrogen object receives a message for an instance method named factoid, it will be redirected to send that message to its HydrogenHelper object (see Figure 3-4).
Figure 3-4. Fast forwarding the factoid method for the Hydrogen class
Great! You have implemented fast forwarding for the Hydrogenclass. Now let’s test the class using fast forwarding. Select themain.m file and update the main() function, as shown inListing 3-12.
Listing 3-12. Testing Fast Forwarding of the Hydrogen Class
int main(int argc, const char * argv[]){ @autoreleasepool { Atom *atom = [Hydrogen hydrogenWithNeutrons:0]; [atom logInfo]; id atom1 = [[Hydrogen alloc] initWithNeutrons:1]; [atom1 logInfo]; // Use message forwarding to get a fact about Hydrogen Hydrogen *atom2 = [Hydrogen hydrogenWithNeutrons:2]; NSString *fact = [atom2 factoid]; [atom2 logInfo:fact]; } return 0;}
On the left side of the editor pane, you’ll probably see anexclamation point in a red circle located on the line NSString *fact = [atom2 factoid]. If you click this exclamation point, you will see an error message (see Figure 3-5).
Figure 3-5. Hydrogen class object messaging error
This error, “No visible @interface for ‘Hydrogen’ declares the selector ‘factoid’,” occurs because the Hydrogen class does not have a factoid instance method declared in its interface. The compiler needs to know the full method signature of every message that a program can possibly send—even those that are forwarded. The solution is to declare the unknown method, either in a class interface or in a category. In Xcode, create a new Objective-C category, enter Helper for the name, and select Atom in the category drop-down list. Make the Elements project its target and the Elements folder the location where the files will be saved. In the Xcode project navigator pane, two new files have been added to the Elements folder:Atom+Helper.h and Atom+Helper.m. These files are the category interface and implementation files. Because you don’t need the implementation, delete the Atom+Helper.m file by selecting it in the navigator pane and then selecting Deletefrom the Xcode Edit menu. Next, in the Atom+Helper.h header file, update the category interface as shown in Listing 3-13.
Listing 3-13. Atom Helper Category Interface
#import "Atom.h"@interface Atom (Helper)- (NSString *) factoid;@end
In Listing 3-13, the factoid method has been added to the category interface. Since the Hydrogen class is a subclass of the Atom class, the compiler will now see the factoid method, thereby resolving the error. The main.m file should include theAtom helper category interface in its list of imports (see Listing 3-14).
Listing 3-14. Imports for main() function
#import <Foundation/Foundation.h>#import "Atom.h"#import "Atom+Nuclear.h"#import "Atom+Helper.h"#import "Hydrogen.h"int main(int argc, const char * argv[]){ ...}
If you compile and run the project, the output should be as shown in Figure 3-6.
- Message Forwarding
- Message Forwarding
- Message Forwarding
- Runtime--Message、Message Forwarding
- Message Forwarding总结
- Runtime Message Forwarding
- Message Forwarding + 动态绑定
- Objective-C Message Forwarding
- Runtime Message Forwarding
- 消息转发(Message Forwarding)
- Message Forwarding (消息传递机制)
- Effective Objective-C 2.0: Item 12: Understand Message Forwarding
- runtime系列4&5---Message Forwarding-消息转发&类型编码
- Objective-C 运行时编程指南 之 Message Forwarding
- port forwarding
- SSH forwarding
- Store Forwarding
- call forwarding
- 黑马程序员:管道流(PipedInputStream)介绍:IO和多线程结合的类
- POJ 1065 Wooden Sticks(zoj 1025) 最长单调子序列
- mysql show (global) status 命令相关
- HTTP协议详解
- 黑马程序员-代理(高新技术)
- Message Forwarding
- C#执行一个目录下所有sql文件
- 利用mysql中show global status和show variables来优化mysql的配置参数
- C#面试问答总结1
- Java中的泛型使用详细介绍
- HTML简介
- 关于C++Release后的优化感想
- android menu菜單控件
- 10918 - Tri Tiling(数论 规律)