4

我想向 NSNumber 类添加一个属性,所以我必须对其进行子类化。文档指出我必须重写所有 NSValue 原始方法。由于 NSValue 文档没有说明哪些方法是原始方法,我认为这两个可能是实例化的原始方法:

– initWithBytes:objCType:  
+ valueWithBytes:objCType:

所以我把我的课设为:

@interface MultipleNumber : NSNumber {  
    NSNumber *_number;  
}  
@property (nonatomic, getter = isMultiple) BOOL multiple;  
@end

@implementation MultipleNumber  
@synthesize multiple=_multiple;  

-(id)initWithBytes:(const void *)value objCType:(const char *)type {  
    self = [super init];  
    if (self) {
        _number=[[NSNumber alloc] initWithBytes:value objCType:type];
    }
    return self;
}

+(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type {
   return [[[MultipleNumber alloc] initWithBytes:value objCType:type] autorelease];
}

-(void)getValue:(void *)value { [_number getValue:value]; }

-(const char *)objCType { return [_number objCType]; }

@end

但是当我调用 [NSNumber numberWithBool:YES] 时,我仍然得到一个 _NSCFBoolean 类,并且没有调用“原始方法”。我怎样才能弄清楚哪些方法被认为是原始的?

4

3 回答 3

7

您无需子类化NSNumber即可添加属性。您可以使用关联引用更轻松地添加属性。子类化NSNumber非常棘手,因为它是一个类集群。


编辑:@Remco 在他对@diablosnuevos 的评论中提出了一个重要的观点,我想在回答中指出:

是的,我终于通过反复试验做了一个子类,因为返回的 NSNumbers 是共享实例,所以存储关联引用也是共享的。– Remco Poelstra 5 月 16 日 9:09

这是一件非常重要的事情要记住。NSNumber缓存从 -1 到 12 的整数并将它们视为单例。在 OSX 10.7 中,NSNumber它被实现为一个标记指针(尚未深入研究那里关联引用的含义)。关键是,虽然关联的引用非常有用,但可能有一些底层的实现细节会让你很头疼。

这里更深层次的教训是,子类化或扩充在任何情况下都NSNumber 可能不是一个好主意。NSNumber是一个非常低级的对象。构建另一个拥有 an 的类几乎肯定会更好NSNumber,就像NSAttributedString拥有 anNSString而不是扩展NSString

我不知道这里要解决的问题的具体情况,但是遇到的问题是一个有趣的教训。

于 2012-05-02T13:30:03.210 回答
5

我发现上面的大多数答案都是不可接受的。很多时候,子类化可能是最好的设计选择。您获得 _NSCFBoolean 的原因是因为这就是便利方法 numberWithBool: 的设计目的——它方便地为您提供具有正确私有子类的 NSNumber。您应该编写自己的便捷方法,即 + (NSNumber*)numberWithMultiple...

于 2012-05-14T16:21:37.123 回答
4

编辑:注意评论中的警告!这对许多类来说都是一个很好的解决方案;它可能对 NSNumber、NSString 以及可能的其他类似 NSArray 等没有好处,因为它们出于性能原因而在幕后使用魔法,这可能会导致意外行为,例如共享实例。

如何为自己省去子类化的痛苦,而是用一个类别来扩展类?

看看这里: http: //oleb.net/blog/2011/05/faking-ivars-in-objc-categories-with-associative-references/

于 2012-05-02T13:33:43.443 回答