gpt4 book ai didi

ios - 如何使用 NSNumber 对象的属性创建类别

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:18:06 29 4
gpt4 key购买 nike

出于各种原因,我需要将默认数字格式(NSNumberFormatter)与NSNumber 对象相关联。即使对于在我控制之外创建的对象,我也想支持它,因此我没有创建 NSNumber 的子类,而是使用了类别和 ObjC associated object functionality。为达到这个:

@interface NSNumber (defaultNumberFormat)
@property (nonatomic,strong) NSNumberFormatter *defaultNumberFormat;
@end

@implementation NSNumber (defaultNumberFormat)

@dynamic defaultNumberFormat;

- (void)setDefaultNumberFormat:(NSNumberFormatter *)format {
[self willChangeValueForKey:@"defaultNumberFormat"];
objc_setAssociatedObject(self, @selector(defaultNumberFormat), format, OBJC_ASSOCIATION_COPY_NONATOMIC);
[self didChangeValueForKey:@"defaultNumberFormat"];
}

- (NSNumberFormatter *)defaultNumberFormat {
return objc_getAssociatedObject(self, @selector(defaultNumberFormat));
}
@end

这在 32 位编译下运行良好,但在 iOS7 下对于 64 位目标,对于某些值,它在 obj_setAssociatedObject 调用时因 EXC_BAD_ACCESS (code=EXC_I386_GPFLT) 而崩溃。

事实证明,原因是 iOS 对具有较小值的选定对象使用 64 位目标的标记指针以提高性能(避免为对象分配内存和 ARC 清理)。这包括一些 NSString、NSNumber 和 NSDate 值。查看更多信息herehere .

那么如何在64位模式下实现一个属性为NSNumber的类别呢?

最佳答案

我第一次尝试解决这个问题时尝试在检测到标记的指针对象时通过异常手动管理关联。这可行,但不是一个实用的解决方案,因为您失去了 ARC 对关联值的所有好处(当标记的指针对象不再使用时,它们不会被清除)。

相反,一个可行的解决方案是使该属性只读,然后在应用关联对象之前使用单独的访问器将标记指针对象转换为普通对象:

@interface NSNumber (defaultNumberFormat)
@property (nonatomic,strong,readonly) NSNumberFormatter *defaultNumberFormat;
- (NSNumber *)applyDefaultNumberFormat:(NSNumberFormatter *)format;
@end

@implementation NSNumber (defaultNumberFormat)

@dynamic defaultNumberFormat;

- (NSNumber *)applyDefaultNumberFormat:(NSNumberFormatter *)format {
NSNumber *newNumber = self;
#ifdef WORKAROUND_IOS_TAGGED_POINTER_ISSUE
unsigned long ptrValue = (unsigned long)self;
if (ptrValue & 0x1) {
// We have a non-aligned pointer - ie a tagged short-cut object stored inside the pointer. objc_setAssociatedObject() is broken for these object types (it will cause memory access faults).
// Transform ourselves into a non-tagged object.
newNumber = [NSDecimalNumber decimalNumberWithDecimal:[self decimalValue]];
ptrValue = (unsigned long)newNumber;
if (ptrValue & 0x1 || ![newNumber isKindOfClass:[NSNumber class]]) {
NSLog(@"Failed to create a non-tagged NSNumber for number: %@ - hence default number format not set", [self description]);
return self;
}
}
#endif
[newNumber willChangeValueForKey:@"defaultNumberFormat"];
objc_setAssociatedObject(newNumber, @selector(defaultNumberFormat), format, OBJC_ASSOCIATION_COPY_NONATOMIC);
[newNumber didChangeValueForKey:@"defaultNumberFormat"];
return newNumber;
}

- (NSNumberFormatter *)defaultNumberFormat {
#ifdef WORKAROUND_IOS_TAGGED_POINTER_ISSUE
unsigned long ptrValue = (unsigned long)self;
if (ptrValue & 0x1)
return nil;
#endif
return objc_getAssociatedObject(self, @selector(defaultNumberFormat));
}

@end

关于ios - 如何使用 NSNumber 对象的属性创建类别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24094700/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com