MAObjCRuntime 是围绕 Objective-C 运行时 API 的 ObjC 包装器。如果这令您困惑,它提供了一个良好面向对象的接口,用于 /usr/include/objc 中的一些 C 函数。
MAObjCRuntime 在 BSD 许可下发布。有关官方许可证,请参阅 LICENSE 文件。
操作从 MARTNSObject.h
开始。向 NSObject
添加了各种方法,以允许查询和操作。其中大多数是类方法,因为它们操作类。还有几个实例方法。所有这些方法都以 rt_
开头,以免与名称冲突。使用 RTMethod
和 RTIvar
类分别表示单个方法和单个实例变量。它们的使用应该相当明显。
您可以使用提供的方法查询任何类的方法、实例变量或其他属性。例如
// get all subclasses of a class
NSArray *subclasses = [MyClass rt_subclasses];
// check out the methods on NSString
NSArray *methods = [NSString rt_methods];
for(RTMethod *method in methods)
NSLog(@"%@", method);
// does it have any ivars?
NSLog(@"%@", [NSString rt_ivars]);
// how big is a constant string instance?
NSLog(@"%ld", (long)[[@"foo" rt_class] rt_instanceSize]);
您可以使用 +rt_addMethod:
添加新方法。您可以使用 RTMethod
上的 -setImplementation:
方法修改现有方法的实现。示例
// swizzle out -[NSObject description] (don't do this)
static NSString *NewDescription(id self, SEL _cmd)
{
return @"HELLO WORLD!";
}
Method *description = [NSObject rt_methodForSelector: @selector(description)];
[description setImplementation: (IMP)NewDescription];
您可以使用 +rt_createSubclassNamed:
或 +rt_createUnregisteredSubclassNamed:
创建新类。注意,如果您想要向类中添加实例变量,则必须使用未注册版本,并在注册类之前添加它们。
还提供了一些实例方法。`-rt_class` 存在是因为 Apple 喜欢篡改 `-class` 的返回值,而 `-rt_class` 总是给出正确的值。`-rt_setClass:` 几乎就是它所说的:设置对象的类。它不会重新分配对象或任何东西,因此新的类最好具有与旧类兼容的内存布局,否则会发生一些荒唐的事情。
在从类获取方法列表后,通常希望在实际的类实例上使用这些方法。`RTMethod` 提供了一个简单的方法来执行此操作,以及一些围绕它的便利包装器。
发送消息的基本方法是 -[RTMethod returnValue:sendToTarget:]
。您像这样使用它
RTMethod *method = ...;
SomeType ret;
[method returnValue: &ret sendToTarget: obj, RTARG(@"hello"), RTARG(42), RTARG(xyz)];
将返回值放在参数列表开头看起来可能很奇怪,但这样最接近正常 `ret = [obj method]` 语法。
所有参数都必须用RTARG
宏包起来。这个宏负责包装每个参数,以便它能够通过可变参数列表}-{转储通过,并且还包含一些关于参数类型的额外元数据,以便代码可以执行一些基本的基本检查。不执行自动类型转换。如果你向需要int
的方法传递了double
,则这个方法会{中止。但是,这种检查仅基于大小,所以如果你在一个期望,你将只得到一个无效的值。
请注意,虽然不能保证100%,但此代码在检测你是否未使用RTARG
宏方面做得相当好,并且会大声发出警告并调用{中止代替以神秘方式崩溃。另外请注意,没有对返回值进行基本检查,所以你必须确保使用正确的类型,并留有足够的空间来保存它。
对于返回对象的函数,提供了-[RTMethod sendToTarget:]
方法,它直接返回id
而不是让你使用按引用返回。这简化了调用此类方法的步骤
RTMethod *method = ...;
id ret = [method sendToTarget: obj, RTARG(@"hello"), RTARG(42), RTARG(xyz)];
还有一个NSObject
类别,它提供了方法,允许你改变顺序以更加自然。例如
RTMethod *method = ...;
id ret = [obj rt_sendMethod: method, RTARG(@"hello"), RTARG(42), RTARG(xyz)];
rt_returnValue:sendMethod:
也采用了相同的概念。
最后,有一对便利方法,该方法接受一个选择器,并将方法查找与实际的消息传递组合在一起
id ret = [obj rt_sendSelector: @selector(...), RTARG(@"hello"), RTARG(42), RTARG(xyz)];
SomeType ret2;
[obj rt_returnValue: &ret2 sendSelector: @selector(...), RTARG(12345)];