【问题标题】:NSCode: encoder and decoder for primitive typesNSCode:原始类型的编码器和解码器
【发布时间】:2012-02-28 11:29:11
【问题描述】:

我试图为我的模型类创建通用编码器和解码器。我试图找到一种方法来为所有类型的属性(对象(NSString、NSNumber、NSArray 等)和原始类型)调用 “编码方法”。我看到有人在做以下事情。我想知道这是否是正确的方法。

属性:

@property (assign,nonatomic) int integerP;
@property (assign,nonatomic) float floatP;
@property (assign,nonatomic) BOOL boolP;

编码器和解码器代码:

- (void)encodeWithCoder:(NSCoder *)encoder
{
    id object2 = [self valueForKey:@"integerP"];
    id object3 = [self valueForKey:@"floatP"];
    id object4 = [self valueForKey:@"boolP"];


    [encoder encodeObject:object2 forKey:@"integerP"];
    [encoder encodeObject:object3 forKey:@"floatP"];
    [encoder encodeObject:object4 forKey:@"boolP"];

    //[self setValue:[NSNumber numberWithInt:90] forKey:@"heightR"];

    //NSLog(@"%@",[self valueForKey:@"heightR"]);


}

- (id)initWithCoder:(NSCoder *)decoder
{
    self = [super init];
    if( self != nil )
    {

        id object2 = [decoder decodeObjectForKey:@"integerP"];
        [self setValue:object2 forKey:@"integerP"];
        id object3 = [decoder decodeObjectForKey:@"floatP"];
        [self setValue:object3 forKey:@"floatP"];
        id object4 = [decoder decodeObjectForKey:@"boolP"];
        [self setValue:object4 forKey:@"boolP"];

    }
    return self;
}

我不确定这是否正确,或者其他程序或对象是否可以写入原始属性的相同内存空间。如果上面的方法是正确的,上面和这个有什么区别:

我认为正确的方式:

- (void)encodeWithCoder:(NSCoder *)encoder
{


    [encoder encodeInt:integerP forKey:@"integerP"];
    [encoder encodeFloat:floatP forKey:@"floatP"];
    [encoder encodeBool:boolP forKey:@"boolP"];

    //[self setValue:[NSNumber numberWithInt:90] forKey:@"heightR"];

    //NSLog(@"%@",[self valueForKey:@"heightR"]);


}

- (id)initWithCoder:(NSCoder *)decoder
{
    self = [super init];
    if( self != nil )
    {
        integerP = [decoder decodeIntForKey:@"integerP"];
        floatP = [decoder decodeFloatForKey:@"floatP"];
        boolP = [decoder decodeBoolForKey:@"boolP"];


    }
    return self;
}

我进行了测试,两种方法都返回了正确的值。

【问题讨论】:

  • 我不明白。已经有编码/解码原始类型的方法,为什么不使用它们?对我来说,第二种方法更正确。

标签: objective-c ios nscoding


【解决方案1】:

这两种方法都可以。

第一个特别聪明,valueForKey: 将始终返回一个 NSObject,即使该值实际上是一个原始值,所以 float/int/bool 类型将由 KVC getter 自动包装在一个 NSNumber 中,并展开在 KVC 设置器中。

也许可以使用它来实现某种通用的编码/解码函数,这些函数对一组属性键进行操作。

但是,第二个示例是执行此操作的标准方式,也是我可能会推荐的方式。有时您必须编写样板代码!

【讨论】:

  • 很高兴知道两者都可以工作并且可以使用。但是,为什么要推荐第二个呢?如果您使用第二种方法,您是否知道任何类型的性能提升? - 现在,我有 2 种选择来编写我的通用编码/解码,要么使用上面发布的第一个编码方法,要么使用包含我所有原始属性的 NSDictionary。你会推荐哪种方式?
  • 我不确定,但我相信性能差异可以忽略不计。如果您将原语存储在 NSDictionary 中,则无论如何都必须先将它们转换为 NSNumber,因此实际上是同一件事。我的建议是手动编写编码/解码,但如果您想尝试通用编码/解码,第一个将是最好的选择。但是,如果性能是一个大问题,你真的应该考虑迁移到 Core Data 模型。 NSCoder 在编码大型对象树时非常慢。
  • 是的,我想这也可能是一个小的性能差异。现在,我想我将使用第一种方法编写通用编码器/解码器。我不相信这会给我带来任何巨大的性能差异,并且会为我节省大量时间用于其他项目。是的,我将对大型对象使用 Core Data 模型,我只打算将 NSCoder 用于小型首选项对象。不过谢谢!
【解决方案2】:

试试这个:

BaseModel.h

@interface BaseModel : NSObject<NSCoding>
@end

BaseModel.m

- (NSArray *)keysForEncoding
{
    [NSException raise:@"keysForEncoding" format:@"keysForEncoding must be implemented in child class!"];
    //example implementation in child class:
    //return @[@"airtime", @"channelID", @"duration", @"programID", @"shortTitle"];
    return nil;
}


-(void)encodeWithCoder:(NSCoder *)aCoder
{
    for(NSString* key in [self keysForEncoding])
    {
        [aCoder encodeObject:[self valueForKey:key] forKey:key];
    }
}

-(id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        for (NSString* key in [self keysForEncoding]) {
            [self setValue:[aDecoder decodeObjectForKey:key] forKey:key];
        }
    }
    return self;
}

然后使用实际数据从该基类派生您的类。

简单类示例:

EPGData.h

    @interface EPGData : BaseModel
    @property(nonatomic, assign) NSTimeInterval airtime; //date in 1970 format
    @property(nonatomic, assign) int channelID;
    @property(nonatomic, assign) float duration; //in seconds
    @property(nonatomic, assign) unsigned int programID;
    @property(nonatomic, strong) NSString* shortTitle;
    @end

EPGData.m

- (NSArray *)keysForEncoding;
{
    return [NSArray arrayWithObjects:@"airtime", @"channelID", @"duration", @"programID", @"shortTitle", nil];
}

【讨论】:

    【解决方案3】:

    你的第一个方法看起来很奇怪!

    在 Objective-C 中 float/int/BOOL 不是“对象”。您可以通过调用将它们转换为NSNumber

    NSNumber *aNumber = [NSNumber numberWithInt:integerP];
    

    但是您的第二个解决方案看起来不错。
    仅将decodeObjectForKey 用于NSArray 等对象或您自己的类(您还需要添加编码/解码方法!)

    让您的手指远离setValuevalueForKey

    【讨论】:

      猜你喜欢
      • 2017-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-05
      相关资源
      最近更新 更多