对于我正在进行的项目,我必须动态地为一些动态属性提供实现。在这样做的过程中,我注意到在测试期间我在imp_implementationWithBlock块中引用的实例变量总是会返回我在声明块时所具有的值,而不是当前实例变量的值。
即:
最后,我只是使用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
答案 0 :(得分:1)
因为您的-(IMP)dynamicImplementation
与:
- (IMP)dynamicImplementation {
id blockSelf = self;
return imp_implementationWithBlock(^NSString * (id _self) {
return blockSelf->_aCustomString;
});
}
它捕获第一个实例并返回其_aCustomString
ivar。
您应该使用_self
:
- (IMP)dynamicImplementation {
return imp_implementationWithBlock(^NSString * (id _self) {
return _self->_aCustomString;
});
}