打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
<objc/rumtime.h>
iOS4高级编程 第二章 2.13.4.3 Objective-C 运行
获取一个类中定义的所有方法
如果你想获取一个类中定义的所有方法的数组,不包含任何它的超类,你可以使用class_copyMethodList()函数。这个函数返回一个类的方法实现的数组,声明如下:[/color]
[color=#231f20]
Method * class_copyMethodList(Class cls, unsigned int *outCount)
第一个参数是类对象,第二个是一个整数的引用。如果你想获得实例方法,你通过类对象。如果,另一方面,你想获得所有方法的列表,你需要通过元对象。这个作为类(需要获得它的方法)的蓝图这个有道理,它是元类对象。返回的数组包括方法类型的指针。当你完成它的时候你需要释放返回的数组。[/color]
[color=#231f20]
让我们通过一个例子说明。考虑下面的类:[/color]
[color=#231f20]
@interface RT5 :NSObject
+(void)simpleS;
+(NSString*)complexS:(NSNumber*)aNumber
andAString:(NSString*)aString;
-(void)simple;
-(NSString*)complex:(NSNumber*)aNumber
andAString:(NSString*)aString;
@end
@implementation RT5
+(void)simpleS{}
+(NSString*)complexS:(NSNumber*)aNumber
andAString:(NSString*)aString{
return @"Hi";
}
-(void)simple{}
-(NSString*)complex:(NSNumber*)aNumber
andAString:(NSString*)aString{
return @"Hello";
}
@end
列出类方法,我们调用到我们listAllMethods()方法,如下:[/color]
[color=#231f20]
listAllMethods(object_getClass([RT5 class]));
在这里,我们通过类RT5的元类作为唯一的参数。我们在类对象中通过运行函数object_getClass()获得元类对象。[/color]
[color=#231f20]
列出所有实例方法,我们通过如下类对象:[/color]
[color=#231f20]
listAllMethods([RT5 class]);
The listAllMethods()function is shown below:
listAllMethods()函数,如下所示:[/color]
[color=#231f20]
void listAllMethods(Classclass){
unsigned int methodCount;
Method *methods = class_copyMethodList(class, &methodCount);
for(int i=0; i < methodCount; i++){
char buffer[256];
SEL name = method_getName(methods);
NSLog(@"The method’s name is %@", NSStringFromSelector(name));
//OR
//NSLog(@"The method’s name is %s", name);
char *returnType = method_copyReturnType(methods);
NSLog(@"The return type is %s", returnType);
free(returnType);
// self, _cmd + any others
unsigned int numberOfArguments=
method_getNumberOfArguments(methods);
for(int j=0; j<numberOfArguments;j++){
method_getArgumentType(methods, j, buffer, 256);
NSLog(@"The type of argument %d is %s", j, buffer);
}
}
free(methods);
}
上述的函数,获得类对象的方法数组通过一个参数开始。获得方法数组后,该方法遍历这个数组记录每个方法的具体属性。上述的方法记录的方法的名称,返回类型,每个属性类型。[/color]
[color=#231f20]
获得返回的方法类型,你可以使用method_copyReturnType()函数声明入戏:[/color]
[color=#231f20]
char *method_copyReturnType(Method m)
获得指定参数的类型,你可以使用method_getArgumentType()函数,声明如下:[/color]
[color=#231f20]
void method_getArgumentType(Method m, unsigned int index,char *dst, size_t dst_len)
你通过作为方法对象的第一个参数。其指定类型是作为第二个参数传递。一个指向存储返回类型的缓冲区的指针通过作为第三个参数。最后,缓冲区的大小通过作为第四个参数。[/color]
[color=#231f20]
例如,这里是输出相关类的方法之一:[/color]
[color=#231f20]
方法的名称是 complexS:andAString:
返回的类型是 @
参数0的类型是@
参数1的类型是:[/color]
[color=#231f20]参数2的类型是@
参数3的类型是@
注意,前两个参数是每个方法的隐藏函数。[/color]
[color=#231f20]
添加一个新方法[/color]
[color=#231f20]
如果你想到一个类里添加一个新方法,你可以使用函数class_addMethod(),声明如下:[/color]
[color=#231f20]
BOOL class_addMethod(Class cls, SEL name, IMP imp, constchar *types)
首先前三个参数你应该很熟悉了。最后一个参数,是你提供编码返回和参数类型的C字符串。这个方法名必须不能被类cls实现。如果它是超类cls之一声明,它会被重写。[/color]
[color=#231f20]
让我们通过一个例子说明。考虑一个类RT6没有定义方法。假设我们想添加一个新的实例方法,selector newOne:withData:签名如下:[/color]
[color=#231f20]
-(NSString*) newOne:(BOOL)flagwithData:(NSData*)data;
C函数实现这个新方法,如下所示:[/color]
[color=#231f20]
NSString* newOneImplementation(id self,SEL _cmd,BOOLflag,NSData* data){
NSLog(@"self: %@, _cmd: %@", self, NSStringFromSelector(_cmd));
NSLog(@"The flag is: %@ and the data is: %@",flag?@"YES":@"NO", data);
return @"Done!";
}
添加一个新方法,我们简单的调用class_addMethod()函数,如下所示:[/color]
[color=#231f20]
class_addMethod([RT6 class], @selector(newOne:withData:),
(IMP)newOneImplementation,"@@:B@");
我们通过类对象,因为它是我们添加的一个实例方法。方法名是通过第二个参数。一个指向我们实现的指针,是通过第三个参数。第四个参数是一个集中编码的C字符串。我们知道,每一个方法的前两个参数是编码为@的对象,和selector编码为:。NSString*返回类型和它的编码为@。我们方法的第一个和第二个参数是BOOL(编码作为B)和NSData*编码为@。注意类型通常列在第一个位。[/color]
[color=#231f20]
一旦我们添加了一个新方法,我们作为任何Objective-C方法调用它。你将,然而,获得一个编译警告。Objective-C编译环境是聪明的,但它不是那么聪明!
RT6 *t = [[[RT6 alloc] init] autorelease];
NSLog(@"%@", [t newOne:YES withData:[NSDatadata]]);
添加一个类方法,通过object_getClass([RT6class])作为class_addMethod()函数的第一个参数。[/color]
[color=#231f20]
发送消息到一个对象[/color]
[color=#231f20]
你已经看到了我们的朋友objc_msgSend()函数。如果你发现需要使用此功能,你可以在你的地方使用它。例如,考虑下面的类:[/color]
[color=#231f20]
@interface RT7 : NSObject
+(NSUInteger) lengthS:(NSString*)theString;
-(NSUInteger) length:(NSString*)theString;
@end
@implementation RT7
+(NSUInteger) lengthS:(NSString*)theString{
return [theString length];
}
-(NSUInteger) length:(NSString*)theString{
return [theString length];
}
@end
调用实例方法length:,你可以写成下面的:[/color]
[color=#231f20]
RT7 *rt = [[[RT7 alloc] init] autorelease];
NSUInteger value;
value = ((int(*)(id, SEL, NSString*))objc_msgSend)(
rt, @selector(length:), @"hi");
构造objc_msgSend()函数是可选的。它不仅能一处编译器警告。[/color]
[color=#231f20]
调用类方法lengthS:,你可以写成[/color]
[color=#231f20]
value = ((int(*)(id, SEL, NSString*))objc_msgSend)(
[RT7 class], @selector(lengthS:), @"hello");
访问实例变量[/color]
[color=#231f20]
你可以直接访问对象的实例变量。访问一个实例变量,使用object_getInstanceVariable()函数,声明如下[/color]
[color=#231f20]
Ivar
object_getInstanceVariable(idobj, const char *name, void **outValue);
返回Ivar类型的值,实例变量运行期间的类型。这个返回值表示你访问的实例变量。你通过在第一个参数检索实例对象。实例变量的名字通过C字符串,和第三个参数是void*指针,哪里实例变量的值会被存储。[/color]
[color=#231f20]
考虑下面的类:[/color]
[color=#231f20]
@interface RT8 : NSObject{
NSNumber *val;
}
@property (nonatomic, assign) NSNumber *val;
@end
@implementation RT8
@synthesize val;
@end
下面,让我们创建一个新实例,并改变实例变量的值:[/color]
[color=#231f20]
RT8 *rt8 = [[[RT8 alloc] init] autorelease];
rt8.val = [NSNumber numberWithInt:99];
方位实例变量的值,你可以写类似下面的声明:[/color]
[color=#231f20]
void *outValue;[/color]
[color=#231f20]object_getInstanceVariable(rt8, "val",&outValue);
NSLog(@"The number is %d",[(NSNumber*) outValue intValue]);
动态创建新类[/color]
[color=#231f20]
如果你的应用程序在运行期间需要创建一个新类,你可以使用运行期间提供的支持,达到你的目标。[/color]
[color=#231f20]
创建一个新类,你首先使用函数objc_allocateClassPair()创建它和它的元类。这个函数声明如下:[/color]
[color=#231f20]
Class objc_allocateClassPair(Class superclass, const char*name,
size_t extraBytes)
第一个参数是超类的类对象。第二个参数是新类的C字符串名。第三个和最后一个参数指定的额外的分配字节和通常为0。[/color]
[color=#231f20]
创建完新类后,你可以添加实例变量和实例/类方法。然后,你使用函数objc_registerClassPair()通过调用objc_allocateClassPair函数的返回值注册类和它的元类。[/color]
[color=#231f20]
让我们通过详细的例子说明这个话题。考虑下面现存的类:[/color]
[color=#231f20]
@interface RT9 : NSObject{
NSNumber*val;
}
@property(nonatomic, retain) NSNumber *val;
@end
@implementation RT9
@synthesize val;
-(id)init{
if(self = [super init]){
self.val = [NSNumber numberWithInt:99];
}
return self;
}
-(void)dealloc{
NSLog(@"dealloc in super");
self.val = nil;
[super dealloc];
}
@end
RT9是简单的类,我们想使用被叫做MyAwesomeClass新类元类。创建一个新类,我们从下面的声明开始:[/color]
[color=#231f20]
Class dynaClass =
objc_allocateClassPair([RT9 class],"MyAwesomeClass", 0);
然后,我们使用方法class_addIvar添加一个实例变量。声明如下:[/color]
[color=#231f20]
BOOL class_addIvar(Class cls, const char *name, size_tsize, uint8_t alignment, const char *types)
第一个参数是一个类对象。这个类对象不是一个元类的引用。第二个参数是新变量名的C字符串。第三个参数是新实例变量的大小。第四个参数是对齐的存储。第五个和最后一个是参数是实例变量的编码类型。当且仅当实例变量创建成功函数返回YES。[/color]
[color=#231f20]
添加一个实例变量叫做NSArray*类型的vertices,我们写类似下面的东西:[/color]
[color=#231f20]
class_addIvar(dynaClass,"vertices", sizeof(id), log2(sizeof(id)), "@");
接下来,让我们添加方法many和dealloc:[/color]
[color=#231f20]
class_addMethod(dynaClass, @selector(many),
(IMP)manyImplementation, "@@:");
class_addMethod(dynaClass, @selector(dealloc),
(IMP)deallocImplementation, "v@:");
最后,我们注册类和它的原味,如下:[/color]
[color=#231f20]
objc_registerClassPair(dynaClass);
many方法的实现展示如下:[/color]
[color=#231f20]NSNumber* manyImplementation(id self, SEL _cmd){
void *outValue1;
void *outValue2;
object_getInstanceVariable(self, "vertices", &outValue1);
object_getInstanceVariable(self, "val", &outValue2);
return [NSNumber numberWithInt:
((NSArray*)outValue1).count +
[(NSNumber*)outValue2 intValue]];
}
注意我们怎样访问实例变量,val,从元类继承。[/color]
[color=#231f20]
dealloc方法的实现如下[/color]
[color=#231f20]
void deallocImplementation(id self, SEL _cmd){
void *outValue;
object_getInstanceVariable(self, "vertices", &outValue);
[(id) outValue release];
object_setInstanceVariable(self, "vertices", nil);
struct objc_super obS;
obS.super_class = [self superclass];
obS.receiver = self;
objc_msgSendSuper(&obS, @selector(dealloc));
}
这里,我们恢复NSArray对象和release它。我们传播dealloc到它的父类,使用函数objc_msgSendSuper()发送一个对象到父类,声明如下:[/color]
[color=#231f20]
id objc_msgSendSuper(struct objc_super*super, SEL op, ...);
第一个参数是objc_super结构,第二个是selector。objc_super结构声明如下:[/color]
[color=#231f20]
struct objc_super {
id receiver;
Class super_class;
};
下面展示的是怎样使用这个新类:[/color]
[color=#231f20]
//create an object of this class
id dynaObject = [[NSClassFromString(@"MyAwesomeClass") alloc]init];
// OR [dynaClass alloc]
//assign a value to an instance variable of this class
object_setInstanceVariable(dynaObject, "vertices",
[[NSArray arrayWithObjects:@"Bart", @"lisa", nil]retain]);
//invoke a method on this class
NSNumber *numb = [dynaObject many];
NSLog(@"The returned number is %@", numb);
[dynaObject release];
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Java的this和重载
Java类和对象及实例
如何对webbrowser和IE编程(六)
100多道经典的JAVA面试题及答案解析(2)
Objective-C入门教程04:消息(方法)
一个月的JAVA总结
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服