【问题标题】:Objective-C Custom Getter / SetterObjective-C 自定义 Getter / Setter
【发布时间】:2023-03-12 21:44:01
【问题描述】:

我正在使用以下由 Xcode 自动生成的 NSManagedObject:

@interface Portion :  NSManagedObject  
{
}

@property (nonatomic, retain) NSNumber * volume;

我想创建一个自定义 getter/setter 以根据用户设置的内容在 ml/oz 之间进行转换,这样数据库始终存储相同的值并自动转换为首选单位。我最近的尝试是这样的:

#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 调用最终会调用自身导致无限循环。我猜有办法做到这一点,但我不知道它是什么,有什么想法吗?

【问题讨论】:

  • psst。你的意思可能是:[@"oz" isEqualToString:[SettingHandler getUnitsTypeShort]] 而不是:[SettingHandler getUnitsTypeShort] == @"oz"

标签: iphone objective-c core-data


【解决方案1】:

很抱歉扮演魔鬼的拥护者,但是 IMO,您似乎正在尝试解决如何以太低的级别向用户显示值(在模型对象本身中;参见 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,您可以使用 if then 逻辑返回一个字符串“2.0 cups”而不是 16 oz。

【讨论】:

  • +大约一百万。这是迄今为止发布的问题的最佳解决方案。当然,你也需要一个 numberFromString: 实现。
【解决方案2】:

查看核心数据编程指南中的"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"];

并在getter中进行相应的修改。

【讨论】:

    【解决方案3】:

    尝试改用[self setPrimitiveValue:number forKey:@"volume"];

    【讨论】:

      【解决方案4】:

      我会建议另一种方法。决定规范表示 - 盎司或毫升。这就是实际存储的卷。然后声明以下 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];
      }
      

      【讨论】:

        猜你喜欢
        • 2012-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-09
        • 2017-10-31
        相关资源
        最近更新 更多