【发布时间】:2014-08-13 14:12:47
【问题描述】:
对于我正在处理的项目,我必须动态地提供一些动态属性的实现。这样做时,我注意到在测试期间我在 imp_implementationWithBlock 块中引用的实例变量将始终返回它在声明块时的值,而不是当前实例变量的值。
即:
- 我的第一个实例的实例变量值为@"test1"
- 在第一次初始化时,如果我的动态方法还不存在,我使用 imp_implementationWithBlock 和 class_addMethod 创建它。
- 然后,如果访问动态属性 obj1.dynProp,我将返回我的 @"test1" 值。
- 我用 @"test2" 的值实例化了第二个对象。
- 动态属性已经有一个实现,所以我在这方面没有做更多的事情。
- 现在,如果我访问动态属性 obj2.dynProp,我仍然会返回 @"test1" 值。
最后,我只是简单地使用 class_getInstanceVariable 来检索实例变量,一切正常,但我想了解为什么它一开始就不起作用。实例变量显然似乎与 imp_implementationWithBlock 中的块一起被复制,但我找不到相关文档来准确解释正在发生的事情。
这是一个重现问题的简单类:
DRTestObject.h
#import <UIKit/UIKit.h>
@interface DRTestObject : NSObject
- (instancetype)initWithString:(NSString *)aCustomString;
@property (readonly, nonatomic) NSString *customString;
@end
DRTestObject.m
#import "DRTestObject.h"
#import <objc/runtime.h>
/*************************************************************************************/
@interface DRTestObject()
{
NSString *_aCustomString;
}
@end
/*************************************************************************************/
@implementation DRTestObject
@dynamic customString;
- (instancetype)initWithString:(NSString *)aCustomString
{
self = [self init];
if(self){
_aCustomString = aCustomString;
[self addDynamicMethod];
}
return self;
}
- (void)addDynamicMethod
{
if(![self alreadyHasImplementation]){
IMP dynamicIMP = [self dynamicImplementation];
class_addMethod([self class], NSSelectorFromString(@"customString"), dynamicIMP, [@"@NSString@:" UTF8String]);
}
}
- (BOOL)alreadyHasImplementation
{
Method method = class_getInstanceMethod([self class], NSSelectorFromString(@"customString"));
return method != NULL;
}
- (IMP)dynamicImplementation
{
return imp_implementationWithBlock(^NSString * (id _self) {
return _aCustomString;
});
}
@end
测试调用
DRTestObject *testObj1 = [[DRTestObject alloc] initWithString:@"testObj1"];
NSLog(@"TestObj1 Custom String : %@", testObj1.customString); // Returns testObj1
DRTestObject *testObj2 = [[DRTestObject alloc] initWithString:@"testObj2"];
NSLog(@"TestObj2 Custom String : %@", testObj2.customString); // Also returns testObj1
【问题讨论】:
标签: objective-c objective-c-runtime