有没有办法通过使用Objective c runtime来访问任何类的私有实例变量的地址?
例如:
self.navigationItem.title
有没有办法获取UINavigationItem类的_title ivar的地址?
由于
答案 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_getInstanceVariable
或object_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;
}