6

モデルクラス用の汎用エンコーダーとデコーダーを作成しようとしていました。オブジェクト(NSString、NSNumber、NSArrayなど)とプリミティブ型のいずれかのすべてのタイプのプロパティに対して「encodeメソッド」を呼び出す方法を見つけようとしていました。そして、私は誰かが次のことをしているのを見ました。そして、私はこれがそれを行う正しい方法であるかどうか疑問に思いました。

プロパティ:

@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;
}

テストしたところ、両方のメソッドが正しい値を返しました。

4

3 に答える 3

8

どちらの方法でも機能します。

1つ目は特に賢く、valueForKey:値が実際にはプリミティブであっても常にNSObjectを返すため、float / int / bool型はKVCゲッターによってNSNumberに自動的にラップされ、KVCセッターでアンラップされます。

これを使用して、プロパティキーの配列を操作するある種の汎用エンコード/デコード関数を実装できる場合があります。

ただし、2番目の例はそれを行うための標準的な方法であり、おそらく私がお勧めする方法です。ボイラープレートコードを書かなければならないこともあります!

于 2012-02-28T11:54:38.560 に答える
1

あなたの最初の方法は非常に奇妙に見えます!

Objective-Cfloat/int/BOOLでは「オブジェクト」ではありません。NSNumber次のように呼び出すことで、それらをに変換できます。

NSNumber *aNumber = [NSNumber numberWithInt:integerP];

しかし、2番目の解決策は問題ないようです。などのオブジェクトまたは独自のクラス(コーディング/デコードメソッドも追加する必要がある場合)に
のみ使用してください。decodeObjectForKeyNSArray

setValueそして、から指を離しますvalueForKey

于 2012-02-28T11:42:23.617 に答える
1

これを試して:

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];
}
于 2014-12-12T09:35:57.713 に答える