NSCode: encoder and decoder for primitive types

I tried to create a common encoder and decoder for my model classes. I tried to find a way to call the "encoding method" for all types of properties, or objects (NSString, NSNumber, NSArray, etc.), and primitive types. And I saw someone do the following. And I was wondering if this is the right thing to do.

Properties:

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

Enconder and Decoder Code:

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

I was not sure if this was correct, or if another program or object could write primitive properties in the same memory space. If the above method is correct, what is the difference between the above and the following:

What I thought was right:

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

I tested and both methods returned the correct values.

+6
source share
3 answers

Both methods will work.

The first one is especially smart, since valueForKey: will always return an NSObject, even if that value is really primitive, so the float / int / bool types will be automatically packed into NSNumber using the KVC getter and deployed to the KVC installer.

Perhaps it will be possible to implement some common encoding / decoding functions that work with an array of property keys.

However, the second example is the standard way to do this and the way I probably recommend it. Sometimes you have to write boilerplate code!

+8
source

At first you look very strange!

There is no "Object" in Objective-C float/int/BOOL . You can convert them to NSNumber by calling:

 NSNumber *aNumber = [NSNumber numberWithInt:integerP]; 

But your second solution looks great.
Use only decodeObjectForKey for objects like NSArray etc., or your own class (where you also need to add encoding / decoding methods!)

And leave your fingers off setValue and valueForKey .

+1
source

Try the following:

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

Then deduce from this base class your class with the actual data.

An example of a simple class:

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
source

Source: https://habr.com/ru/post/909540/


All Articles