我试图为我的模型类创建一个通用的编码器和解码器。我试图找到一种方法来为所有类型的属性(对象(NSString,NSNumber,NSArray等)和原始类型)调用“编码方法”。我看到有人在做以下事情。我想知道这是否是一种正确的方法。
属性:
@property (assign,nonatomic) int integerP;
@property (assign,nonatomic) float floatP;
@property (assign,nonatomic) BOOL boolP;
Enconder和解码器代码:
- (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;
}
我测试了,两种方法都返回了正确的值。
答案 0 :(得分:8)
这两种方法都有效。
第一个特别聪明,因为valueForKey:
将始终返回一个NSObject,即使该值实际上是一个原语,所以float / int / bool类型将由KVC getter自动包装在NSNumber中,并在KVC二传手中打开。
可能可以使用它来实现某些属性键上运行的通用编码/解码函数。
然而,第二个例子是标准的方法,以及我可能推荐的方式。有时你必须编写样板代码!
答案 1 :(得分:1)
你第一种方法看起来很奇怪!
在Objective-C float/int/BOOL
中不是“对象”。您可以通过调用:
NSNumber
NSNumber *aNumber = [NSNumber numberWithInt:integerP];
但是你的第二个解决方案看起来很好
仅对decodeObjectForKey
等对象使用NSArray
或您自己的类(您还需要添加编码/解码方法!)
然后离开setValue
和valueForKey
。
答案 2 :(得分: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];
}