2010-11-10 34 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]; 
}