我们现在来做一件被认为是very bad的事情,如题所示;无论实例变量是私有的、保护的都可以通过地址访问到,并且还可以修改之。这可以称之为所谓的“超级键值编码”。
首先上代码:
#import <Foundation/Foundation.h>
@interface Foo:NSObject{
NSString *name;
}
@property int id_num;
@end
@implementation Foo
-(id)init{
self = [super init];
if(self){
name = @"lovely panda";
_id_num = 11;
}
return self;
}
-(NSString *)description{
return [NSString stringWithFormat:@"%@#%@:%d",[self class],name,self.id_num];
}
@end
typedef unsigned long long ULL;
int main(void){
@autoreleasepool{
Foo *f = [Foo new];
NSLog(@"%@",f);
void *p = (__bridge void *)f;
int *offset_id_num = p + 16;
void *offset_name = p + 8;
ULL name_addr_val = *(ULL *)(offset_name);
NSString *name = (__bridge id)(void*)name_addr_val;
NSLog(@"id_num:%d name:%@",*offset_id_num,name);
*offset_id_num = 1000000000;
*(ULL *)offset_name = (ULL)@"hello kitty";
NSLog(@"f now is %@",f);
}
return 0;
}
原理大致如下:
f偏移0的实例变量是isa,接下来依次为name和_id_num,然后就是源代码直接通过地址的读取和设置了。