有没有办法在目标c运行时访问任何类的私有实例变量的地址?

时间:2011-05-17 10:29:23

标签: iphone objective-c cocoa-touch

有没有办法通过使用Objective c runtime来访问任何类的私有实例变量的地址?

例如:

 self.navigationItem.title 

有没有办法获取UINavigationItem类的_title ivar的地址?

由于

2 个答案:

答案 0 :(得分:4)

明显的观察结果:self.navigationItem.title可能不是一个实例变量,因为getter可以做任何它喜欢生成结果的东西,点符号只是调用getter。即使它是此版本操作系统中的实例变量,也可能不是过去的,也可能不是将来。即使title由实例变量直接支持,它也可能不会被命名为_title - 它可以被称为任何东西。

即使在您确实知道某个类具有特定实例变量的情况下,也会从Objective-C 2.0中删除相关机制。在较旧的运行时下,您可以使用:

#import <objc/runtime.h>

...
Ivar instanceVariable = class_getInstanceVariable([instance class], "varName");
// yes, really, a C-style string

NSLog(@"offset of that var is %d", instanceVariable->ivar_offset);

或者,类似地:

struct exampleClassStruct
{
    @defs(exampleClass);
};
// this is now a struct with the same layout all the same instance variables
// as exampleClass

但是,您现在会遇到诸如“非脆弱ABI中的@defs应用无效”之类的错误。所以,总之:你不能做你想做的事。可能最接近的是使用class_GetProperty,它就像点符号一样 - 不关心内存布局或事物是否具有相同的名称,甚至实际上是实例变量。如果失败了,可以使用class_getInstanceMethod(在同一页面上)获取指向getter的C函数指针。

编辑:在遵循下面的alastair评论后,快速额外观察是runtime提供id object_getIvar(id object, Ivar ivar)link)和一组等效,这是不透明的方式获得和在特定类上设置实例变量,因为它们的地址现在已被遮挡。那些从你得到的Ivar class_getInstanceVariableobject_getInstanceVariable所以可能没有做任何复杂的查找,并解释为什么即使关联的结构现在没有任何公共成员,你仍然可以获得Ivars。

EDIT2:请参阅以下alastair的讨论;根据您对文档的解释,object_getInstanceVariable的最终参数和/或ivar_getOffset的结果可用于执行您想要的操作。假设你采用与alastair相同的读数,那么下列任何一个都可以做你想要的(即席编码):

#import <objc/runtime.h>

void *pointerToInstanceVariableA(id object, const char *variableName)
{
    Ivar instanceVar = class_getInstanceVariable([object class], variableName);
    return (unsigned char *)object + ivar_getOffset(instanceVar);
}

void *pointerToInstanceVariableB(id object, char *variableName)
{
    void *returnValue;
    Ivar instanceVar = object_getInstanceVariable(object, variableName, &returnValue);
    return returnValue;
}

答案 1 :(得分:-1)

我有一个视图控制器,我需要基类的属性。它的名字被定义为

@property ( nonatomic, strong ) NSString *ModuleName;

在不知道类

的情况下访问它的代码

获取自定义视图控制器实例的代码

    id viewCtrl = [appDelegate returnTestView];

现在我抓住了价值(没有任何类的知识)

    Ivar instanceVariable = class_getInstanceVariable([viewCtrl class], "ModuleName");
    NSString *privateValue = (NSString *) object_getIvar(viewCtrl, instanceVariable);
    NSLog(@"Your value is %@", privateValue);

appDelegate中的实际方法是

- (id)returnTestView {
    return [[TestViewController alloc] init];
}

我的自定义视图控制器的初始化

@interface TestViewController : UIViewController

- (id)init {
    self = [super init];
    if (self) {
        // Custom initialization
        self.ModuleName = @"Hello World";
    }
    return self;
}