在 ARC 下运行时添加 __strong ivar
add __strong ivar at runtime under ARC
@interface 中声明的普通 ivar 是 __strong 默认值。
@interface XLPerson : NSObject {
NSString *name; // __strong default
}
@end
现在,我在运行时在 class 上面创建:
Class XLPerson = objc_allocateClassPair([NSObject class], "XLPerson", 0);
size_t size = sizeof(NSString*);
class_addIvar(XLPerson, "name", size, log2(align), @encode(NSString*)));
objc_registerClass(XLPerson);
但是,名为 "name" 的 ivar 不是 __strong ivar。
当我使用 object_setIvar()
时,Ivar 无法保存 newValue(它将在自动释放池结束时被释放)。
id person = [[XLPerson alloc] init];
Ivar ivar = class_getInstanceVariable(XLPerson, "name");
@autoreleasepool {
object_setIvar(person, ivar, [NSString stringWithFormat@"Stack%@", @"Overflow"]);
// @"Whosebug" will be deallocated.
}
NSLog(@"%@", object_getIvar(person, ivar));
// BAD_ACCESS *** -[CFString retain]: message sent to deallocated instance 0x1004002f0
然后我找到两个函数class_setIvarLayout
和class_setWeakIvarLayout
,但是Objective-C Runtime Reference
中没有任何有用的信息。
那么,如何将 __strong Ivar 添加到我在运行时创建的 class 中?
您需要将 ivar 布局设置为 class,在您的情况下(单个强大的 ivar):
class_setIvarLayout(class, (const uint8_t *)"\x01");
然后告诉运行时你的 class 是在 ARC 下管理的:
static void fixup_class_arc(Class class) {
struct {
Class isa;
Class superclass;
struct {
void *_buckets;
uint32_t _mask;
uint32_t _occupied;
} cache;
uintptr_t bits;
} *objcClass = (__bridge typeof(objcClass))class;
#if !__LP64__
#define FAST_DATA_MASK 0xfffffffcUL
#else
#define FAST_DATA_MASK 0x00007ffffffffff8UL
#endif
struct {
uint32_t flags;
uint32_t version;
struct {
uint32_t flags;
} *ro;
} *objcRWClass = (typeof(objcRWClass))(objcClass->bits & FAST_DATA_MASK);
#define RO_IS_ARR 1<<7
objcRWClass->ro->flags |= RO_IS_ARR;
}
在你的 class 注册后调用它,这非常棘手而且可能不稳定,我更喜欢属性而不是 ivars。
我的中文博客,link here
@interface 中声明的普通 ivar 是 __strong 默认值。
@interface XLPerson : NSObject {
NSString *name; // __strong default
}
@end
现在,我在运行时在 class 上面创建:
Class XLPerson = objc_allocateClassPair([NSObject class], "XLPerson", 0);
size_t size = sizeof(NSString*);
class_addIvar(XLPerson, "name", size, log2(align), @encode(NSString*)));
objc_registerClass(XLPerson);
但是,名为 "name" 的 ivar 不是 __strong ivar。
当我使用 object_setIvar()
时,Ivar 无法保存 newValue(它将在自动释放池结束时被释放)。
id person = [[XLPerson alloc] init];
Ivar ivar = class_getInstanceVariable(XLPerson, "name");
@autoreleasepool {
object_setIvar(person, ivar, [NSString stringWithFormat@"Stack%@", @"Overflow"]);
// @"Whosebug" will be deallocated.
}
NSLog(@"%@", object_getIvar(person, ivar));
// BAD_ACCESS *** -[CFString retain]: message sent to deallocated instance 0x1004002f0
然后我找到两个函数class_setIvarLayout
和class_setWeakIvarLayout
,但是Objective-C Runtime Reference
中没有任何有用的信息。
那么,如何将 __strong Ivar 添加到我在运行时创建的 class 中?
您需要将 ivar 布局设置为 class,在您的情况下(单个强大的 ivar):
class_setIvarLayout(class, (const uint8_t *)"\x01");
然后告诉运行时你的 class 是在 ARC 下管理的:
static void fixup_class_arc(Class class) {
struct {
Class isa;
Class superclass;
struct {
void *_buckets;
uint32_t _mask;
uint32_t _occupied;
} cache;
uintptr_t bits;
} *objcClass = (__bridge typeof(objcClass))class;
#if !__LP64__
#define FAST_DATA_MASK 0xfffffffcUL
#else
#define FAST_DATA_MASK 0x00007ffffffffff8UL
#endif
struct {
uint32_t flags;
uint32_t version;
struct {
uint32_t flags;
} *ro;
} *objcRWClass = (typeof(objcRWClass))(objcClass->bits & FAST_DATA_MASK);
#define RO_IS_ARR 1<<7
objcRWClass->ro->flags |= RO_IS_ARR;
}
在你的 class 注册后调用它,这非常棘手而且可能不稳定,我更喜欢属性而不是 ivars。
我的中文博客,link here