object_setInstanceVariable
并且object_getInstanceVariable
实际上应该仅用于对象(尽管接口声明似乎另有说明)。您不应该将它们用于内置函数。
更合适的方法是使用class_getInstanceVariable
and ivar_getOffset
。
例如...
static void* getIvarPointer(id object, char const *name) {
Ivar ivar = class_getInstanceVariable(object_getClass(object), name);
if (!ivar) return 0;
return (uint8_t*)(__bridge void*)object + ivar_getOffset(ivar);
}
那里的转换基本上将对象指针转换为指向字节的指针,因此可以将其添加到偏移量(这为我们提供了指向 iVar 的指针)。我们必须通过void*
第一个,因为 ARC 不允许直接转换为uint8_t*
.
它的用途可以这样证明......
@implementation Foo {
CGRect _rect;
}
- (CGRect*)rectPointer {
CGRect *ptr = getIvarPointer(self, "_rect");
NSAssert(ptr == &_rect, @"runtime discovered pointer should be same as iVar pointer");
return ptr;
}
现在,您有办法获取任何 iVar 的指针......只需void*
适当地转换返回的值。
顺便说一句,我一般不建议这样做,但像任何工具一样,运行时函数也有用途。
哎呀。忘记显示设置值...
CGRect *rectPtr = getIvarPointer(someObject, "_rect");
if (rectPtr) {
*rectPtr = CGRectMake(1, 2, 3, 4);
} else {
// Handle error that the ivar does not exist...
}
编辑
对不起,还不是很清楚。我应该得到这个类型(CGRect*)然后将它传递给object_setInstanceVariable吗?另外,我有一个错误“未定义的符号“_getIvarPointer”” - 请让我知道我应该包含什么 H 文件 – Dmitry
不,您根本不应该使用object_setInstanceVariable
。它应该仅用于作为对象的实例变量。你的是一个 CGRect,所以你根本不应该使用那个函数。
像最后一个例子一样使用它。也许这个更清楚一点(取自您的示例)。
而不是像您提出的问题那样做:
object_setInstanceVariable(obj, "_variable", point);
做这个...
// Get a pointer to the instance variable. Returns NULL if not found.
CGPoint *pointPtr = getIvarPointer(obj, "_variable");
if (pointPtr) {
// Now, assign to the point, by de-referencing the pointer.
*pointPtr = point;
}
请注意,我将getIvarPointer
函数定义为static
具有文件本地范围。它不是苹果提供的函数——你必须编写它。如果您要在多个地方使用它,您需要删除它static
以便链接器可以找到它。