NSObject 方法
除了个别例外,Cocoa 中大部分类都是 NSObject 的子类,因此大部分对象都继承了它所定义的方法。
NSObject 提供了一些简单的查询运行时系统信息的方法:
1 - (BOOL)isKindOfClass:(Class)aClass; 2 - (BOOL)isMemberOfClass:(Class)aClass; 3 - (BOOL)conformsToProtocol:(Protocol *)aProtocol; 4 5 - (BOOL)respondsToSelector:(SEL)aSelector;
第1行判断instance的class类型
第2行判断Member是否属于类
第3行判断委托是否属于类
第4行判断方法是否属于类
测试
1 //test Member 2 BOOL bMember=[@"sName" isMemberOfClass:[self class]]; 3 BOOL bMember1=[@"sName" isMemberOfClass:[self class]]; 4 NSLog(@"bMember:%d,bMember1:%d",bMember,bMember1); 5 6 //test Method 7 BOOL bMethod=[@"showBook" isMemberOfClass:[self class]]; 8 BOOL bMethod1=[@"showBook" isMemberOfClass:[self class]]; 9 NSLog(@"bMethod:%d,bMethod1:%d",bMethod,bMethod1); 10 11 //test Protocol 12 BOOL bProtocol=[self conformsToProtocol:@protocol(vcDelegate)]; 13 NSLog(@"bprotocol:%d",bProtocol);
消息传递
在 Objective-C,直到运行时消息才会绑定到方法实现。
编译器把消息表达式(message expression)转换为调用 Objective-C 运行时函数 objc_msgSend
[receiver message] -> objc_msgSend(receiver, selector)
id objc_msgSend(id theReceiver, SEL theSelector, ...)
Sends a message with a simple return value to an instance of a class.
使用 objc_msgSend 函数,需要引入 Objective-C 运行时头文件:#import <objc/message.h>
[self test];
objc_msgSend(self, @selector(test));
通过定义在 NSObject 类中的方法 methodForSelector: ,你可以请求一个方法实现过程(procedure)的指针。
- (IMP)methodForSelector:(SEL)aSelector
Locates and returns the address of the receiver’s implementation of a method so it can be called as a function.
调用 IMP,头两个需要传递的参数,第一个是消息接收的对象,第二个是 selector。
IMP test = [self methodForSelector:@selector(test)];
test(self, @selector(test));
动态方法
有些情况下,我们会想要提供动态的方法实现。
Objective-C 通过使用 @dynamic 声明属性(property)来告诉编译器,属性(property)相关的方法将会动态地提供。
你可以通过实现方法 resolveInstanceMethod: 和 resolveClassMetho: 为相应的一个实例和类方法来动态地提供一个 selector 实现。
- + (BOOL)resolveInstanceMethod:(SEL)name
Dynamically provides an implementation for a given selector for an instance method. - + (BOOL)resolveClassMethod:(SEL)name
Dynamically provides an implementation for a given selector for a class method.
定义一个 User 类
在 .h 文件,定义属性 name
以往,会在相应的 .m 文件,使用 @synthesize 声明属性 name,这样编译器会自动生成相应的 setter 和 getter 方法
但是,当使用 @dynamic 声明属性 name 时,就必须自己提供相应的 setter 和 getter 方法
Override + (BOOL)resolveInstanceMethod:(SEL)name 方法
当类实例调用 - (void)setName:(NSString) aName 或 -(NSString *)name 方法时,就为其动态地提供方法实现
1 #import <Foundation/Foundation.h> 2 3 @interface User : NSObject { 4 NSString *name; 5 } 6 7 @property (nonatomic, retain) NSString *name; 8 9 @end
1 #import "User.h" 2 #import <objc/runtime.h> 3 4 @implementation User 5 6 @dynamic name; 7 8 - (void)dynamicSetName:(NSString *) aName { 9 if (name != nil) { 10 [name release]; 11 name = nil; 12 } 13 [aName retain]; 14 name = aName; 15 } 16 17 - (NSString *)dynamicName { 18 return name; 19 } 20 21 + (BOOL)resolveInstanceMethod:(SEL)sel { 22 NSLog(@"Instance Method: %@", NSStringFromSelector(sel)); 23 if ([@"setName:" isEqualToString:NSStringFromSelector(sel)]) { 24 class_addMethod([self class], sel, [self instanceMethodForSelector:@selector(dynamicSetName:)], "v@:"); 25 return YES; 26 } else if ([@"name" isEqualToString:NSStringFromSelector(sel)]) { 27 class_addMethod([self class], sel, [self instanceMethodForSelector:@selector(dynamicName)], "@"); 28 return YES; 29 } 30 return [super resolveInstanceMethod:sel]; 31 } 32 33 @end