MAObjCRuntime 0.0.2

MAObjCRuntime 0.0.2

测试已测试
语言语言 Obj-CObjective C
许可证 BSD
发布上次发布2014年5月

未命名 维护。



  • Mike Ash

MAObjCRuntime 是围绕 Objective-C 运行时 API 的 ObjC 包装器。如果这令您困惑,它提供了一个良好面向对象的接口,用于 /usr/include/objc 中的一些 C 函数。

MAObjCRuntime 在 BSD 许可下发布。有关官方许可证,请参阅 LICENSE 文件。

快速入门

操作从 MARTNSObject.h 开始。向 NSObject 添加了各种方法,以允许查询和操作。其中大多数是类方法,因为它们操作类。还有几个实例方法。所有这些方法都以 rt_ 开头,以免与名称冲突。使用 RTMethodRTIvar 类分别表示单个方法和单个实例变量。它们的使用应该相当明显。

查询

您可以使用提供的方法查询任何类的方法、实例变量或其他属性。例如

// 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)];