NSCode: кодер и декодер для примитивных типов - PullRequest
6 голосов
/ 28 февраля 2012

Я пытался создать универсальный кодер и декодер для моих классов моделей.Я пытался найти способ вызвать «метод кодирования» для всех типов свойств, либо объектов (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;
}

Я тестировал и оба методавернул правильные значения.

Ответы [ 3 ]

8 голосов
/ 28 февраля 2012

Оба метода будут работать.

Первый вариант особенно умен, так как valueForKey: всегда будет возвращать объект NSObject, даже если значение на самом деле является примитивом, поэтому типы float / int / bool будут перенесеныв NSNumber автоматически получателем KVC и разворачивается в установщике KVC.

Может быть возможно использовать это для реализации каких-то общих функций кодирования / декодирования, которые работают с массивом ключей свойств.

Однако второй пример - это стандартный способ сделать это, и способ, который я, вероятно, рекомендую.Иногда нужно написать шаблонный код!

1 голос
/ 12 декабря 2014

Попробуйте это:

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];
}
1 голос
/ 28 февраля 2012

Ваш первый способ выглядит очень странно!

В Objective-C float/int/BOOL не являются «объектами».Вы можете преобразовать их в NSNumber, позвонив по номеру:

NSNumber *aNumber = [NSNumber numberWithInt:integerP];

Но ваше второе решение выглядит хорошо.Используйте decodeObjectForKey только для таких объектов, как NSArray и т. Д., Или для своего собственного класса (где вам также необходимо добавить методы кодирования / декодирования!)

И оставьте пальцы от setValue и valueForKey.

...