2010-11-10 38 views
3

我使用下面的NSManagedObject这是自动Xcode中产生的:Objective-C的自定义的getter/setter

@interface Portion : NSManagedObject 
{ 
} 

@property (nonatomic, retain) NSNumber * volume; 

我想创建一个自定义的getter/setter取决于毫升/盎司之间转换是什么用户已经设置,这样数据库总是存储相同的值,并自动转换为首选单位。我的最新尝试如下所示:

#import "Portion.h" 
#import "SettingHandler.h" 

#define MILLILITERS_PER_OUNCE 29.5735296 

@implementation Portion 

@dynamic volume; 

- (void) setVolume:(NSNumber *) number { 
    if ([SettingHandler getUnitsTypeShort] == @"oz") { 
     [self setValue:number forKey:@"volume"]; 
    } else { 
     [self setValue:[NSNumber numberWithFloat:[number floatValue] * MILLILITERS_PER_OUNCE] forKey:@"volume"]; 
    } 
} 

- (NSNumber *) volume { 
    if ([SettingHandler getUnitsTypeShort] == @"oz") { 
     return [self valueForKey:@"volume"]; 
    } else { 
     return [NSNumber numberWithDouble: [[self valueForKey:@"volume"] floatValue] * MILLILITERS_PER_OUNCE]; 
    } 
} 

setVolume调用最终调用自身导致无限循环。我猜测有一种方法可以做到这一点,但我不知道它是什么,有什么想法?

+2

吱吱。你可能的意思是:'[@“oz”isEqualToString:[SettingHandler getUnitsTypeShort]]'而不是:'[SettingHandler getUnitsTypeShort] == @“oz”' – justin 2010-11-10 04:46:12

回答

7

检查出核心数据编程指南中的"Custom Attribute and To-One Relationship Accessor Methods"。基本上,您应该使用原始的getter/setter方法来访问/更改值并使用KVO通知来包装这些调用。

您将需要添加的声明原始访问者:

@interface Portion (PrimitiveAccessors) 
- (NSNumber *)primitiveVolume; 
- (void)setPrimitiveVolume:(NSNumber *)number; 
@end 

然后,你需要更换的每一次出现:

[self setValue:number forKey:@"volume"]; 

有:

[self willChangeValueForKey:@"volume"]; 
[self setPrimitiveVolume:number]; 
[self didChangeValueForKey:@"volume"]; 

,使吸气剂相应的变化。

2

请尝试使用[self setPrimitiveValue:number forKey:@"volume"];代替。

8

对不起,玩恶魔的倡导者,但国际海事组织,似乎你试图解决如何向用户显示价值太低的水平(在模型对象本身,见The Model-View-Controller Design Pattern)。为什么不使用在视图级别工作更多的格式化程序来帮助将原始NSNumber值格式化为将呈现给用户的字符串?

然后,您会有一个可重复使用的类,您可以在任何使用表示卷的数字值的地方使用该类。格式化程序将存储“unitsType”值,以便知道如何正确格式化传入号码。

我做了一个快速的版本使用我现有的格式化,MDFileSizeFormatter之一,作为一个起点:

#import <Foundation/Foundation.h> 

enum { 
    MDVolumeFormatterMetricUnitsType   = 1, 
    MDVolumeFormatterOurStupidAmericanUnitsType = 2, 
    MDVolumeFormatterDefaultUnitsType = MDVolumeFormatterMetricUnitsType 
}; 

typedef NSUInteger MDVolumeFormatterUnitsType; 


@interface MDVolumeFormatter : NSFormatter { 
    MDVolumeFormatterUnitsType unitsType; 
    NSNumberFormatter   *numberFormatter; 
} 
- (id)initWithUnitsType:(MDVolumeFormatterUnitsType)aUnitsType; 

@property (assign) MDVolumeFormatterUnitsType unitsType; 

@end 

然后.m文件:

#import "MDVolumeFormatter.h" 

#define MILLILITERS_PER_OUNCE 29.5735296 

@implementation MDVolumeFormatter 

@synthesize unitsType; 

- (id)init { 
    return [self initWithUnitsType:MDVolumeFormatterDefaultUnitsType]; 
} 

- (id)initWithUnitsType:(MDVolumeFormatterUnitsType)aUnitsType { 
    if (self = [super init]) { 
     numberFormatter = [[NSNumberFormatter alloc] init]; 
     [numberFormatter setFormat:@"#,###.#"]; 
     [self setUnitsType:aUnitsType]; 
    } 
    return self; 
} 

- (void)dealloc { 
    [numberFormatter release]; 
    [super dealloc]; 
} 

- (NSString *)stringForObjectValue:(id)anObject { 
    if ([anObject isKindOfClass:[NSNumber class]]) { 
     NSString *string = nil; 
     if (unitsType == MDVolumeFormatterMetricUnitsType) { 
      string = [[numberFormatter stringForObjectValue: 
         [NSNumber numberWithFloat: 
         [(NSNumber *)anObject floatValue] * MILLILITERS_PER_OUNCE]] 
         stringByAppendingString:@" mL"]; 

     } else { 
      string = [[numberFormatter stringForObjectValue:anObject] stringByAppendingString:@" oz"]; 
     } 
     return string; 
    } 
    return nil; 
} 

@end 

这可能扩展到对传入值进行测试并自动确定适当的音量单位。例如,如果floatValue是16.0,那么可以使用逻辑来返回一串“2.0杯”而不是16盎司。

+1

+约一百万。这是迄今为止发布的问题的最佳解决方案。当然你也需要一个numberFromString:实现。 – JeremyP 2010-11-10 10:28:29

2

我会建议另一种方法。决定典型代表 - 无论是盎司还是毫升。这是实际存储的卷的大小。然后声明以下getter/setter方法:

- (void) setOunces:(double)ounces; 
- (double) ounces; 

- (void) setMilliliters:(double)milliliters; 
- (double*) milliliters; 

如果规范体积为毫升,则:

- (void) setOunces:(double)ounces 
{ 
[self setVolume:[NSNumber numberWithDouble:(ounces* MILLILITERS_PER_OUNCE)]]; 
} 

- (double) ounces 
{ 
return [[self volume] doubleValue]/MILLILITERS_PER_OUNCE; 
} 

- (void) setMilliliters:(double)milliliters 
{ 
[self setVolume:[NSNumber numberWithDouble:milliliters]]; 
} 

- (double) milliliters 
{ 
return [[self volume] doubleValue]; 
}