YYModel 简介与使用


YYModel 是我写的一个 JSON 模型转换库,功能和 Mantle、JSONModel 差不多,但有着更好的性能和容错性。这里简单介绍一下 YYModel 的使用方法。

1. 简单的 JSON 与 Model 的转换

// JSON:
{
    "uid":123456,
    "name":"Harry",
    "created":"1965-07-31T00:00:00+0000"
}

// Model:
@interface User : NSObject
@property UInt64 uid;
@property NSString *name;
@property NSDate *created;
@end
@implementation User
@end

// 从 JSON 转为 Model:
User *user = [User yy_modelWithJSON:json];

//从 Model 转为 JSON:
NSDictionary *json = [user yy_modelToJSONObject];

如果 Model 属性的类型和 JSON 中的类型不一样,YYModel 会自动进行如下转换:

JSON/Dictionary Model
NSString NSURL,SEL,Class
NSString NSDate parsed with these formats:  
yyyy-MM-dd  
yyyy-MM-dd HH:mm:ss  
yyyy-MM-dd'T'HH:mm:ss  
yyyy-MM-dd'T'HH:mm:ssZ  
EEE MMM dd HH:mm:ss Z yyyy 
NSDate NSString (formatted with ISO8601)"YYYY-MM-dd'T'HH:mm:ssZ" 
NSString/NSNumber C number (BOOL,int,float,NSUInteger,UInt64,...)NaN and Inf will be ignored 
NSNumber NSString (NSNumber.stringValue)
NSValue struct (CGRect,CGSize,...)
NSNull nil,0
"null","nil","no","false",... nil,0
"YES","yes","true",... @(YES)

如果自动转换不能完成,则相应属性会被忽略。

2. 将 Model 的属性匹配到指定的 JSON/NSDictionary 键值:

// JSON:
{
    "n":"Harry Pottery",
    "p": 256,
    "ext" : {
        "desc" : "A book written by J.K.Rowing."
    }
}

// Model:
@interface Book : NSObject
@property NSString *name;
@property NSInteger page;
@property NSString *desc;
@end
@implementation Book
+ (NSDictionary *)modelCustomPropertyMapper {
    return @{@"name" : @"n",
    @"page" : @"p",
    @"desc" : @"ext.desc"};
}
@end

通过实现 协议中的 modelCustomPropertyMapper,可以将 Model 属性的名字对应到 JSON/NSDictionary 相应的字段。

3. Model 属性关联到其他 Model

// JSON:
{
    "author":{
        "name":"J.K.Rowling",
        "birthday":"1965-07-31T00:00:00+0000"
    },
    "name":"Harry Potter",
    "pages":256
}

// Model:
@interface Author : NSObject
@property NSString *name;
@property NSDate *birthday;
@end
@implementation Author
@end

@interface Book : NSObject
@property NSString *name;
@property NSUInteger pages;
@property Author *author;
@end
@implementation Book
@end

默认什么都不用做,YYModel 就可以自动转换。

4. Model 属性是容器类型

@class Shadow, Border, Attachment;

@interface Attributes
@property NSString *name;
@property NSArray *shadows;
@property NSSet *borders;
@property NSMutableDictionary *attachments;
@end

@implementation Attributes
+ (NSDictionary *)modelContainerPropertyGenericClass {
    return @{@"shadows" : [Shadow class],
             @"borders" : Border.class,
             @"attachments" : @"Attachment" };
}
@end

通过实现 协议中的 modelContainerPropertyGenericClass,返回 Model 属性容器中需要存放的对象类型,YYModel 会自动进行处理。对象类型可以是 Class 或者 Class name。

5. 黑名单白名单

@interface User
@property NSString *name;
@property NSUInteger age;
@end

@implementation Attributes
+ (NSArray *)modelPropertyBlacklist {
    return @{@"test1", @"test2"};
}
+ (NSArray *)modelPropertyWhitelist {
    return @{@"name"};
}
@end

如果一个 Model 需要忽略某些属性,则可以通过实现 协议中的 modelPropertyBlacklist 来返回属性名列表,YYModel 会在处理过程中忽略这些属性。

如果一个 Model 只需要处理某些特性的属性,则可以通过实现 协议中的 modelPropertyWhitelist 来返回属性名列表,YYModel 在处理中只会处理列表内的属性。

6. 数据校验与额外的处理

@interface User
@property NSString *name;
@property NSDate *createdAt;
@end

@implementation User
- (BOOL))modelCustomTransformFromDictionary:(NSDictionary *)dic {
    NSNumber *timestamp = dic[@"timestamp"];
    if (![timestamp isKindOfClass:[NSNumber class]]) return NO;
    _createdAt = [NSDate dateWithTimeIntervalSince1970:timestamp.floatValue];
    return YES;
}

- (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic {
    if (!_createdAt) return NO;
    dic[@"timestamp"] = @(n.timeIntervalSince1970);
    return YES;
}
@end

如果一个 Model 需要校验数据有效性,可以通过实现 协议中的 modelCustomTransformFromDictionary 或 modelCustomTransformToDictionary 方法来完成。如果数据校验失败,则可以返回 NO,YYModel 会忽略这个 Model。

在上面两个方法中,也可以对 Model/JSON 进行额外的处理,以转换 YYModel 不支持的类型。

6. Coding/Copying/hash/equal

@interface YYShadow :NSObject <NSCoding, NSCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) CGSize size;
@end

@implementation YYShadow
- (void)encodeWithCoder:(NSCoder *)aCoder { [self yy_modelEncodeWithCoder:aCoder]; }
- (id)initWithCoder:(NSCoder *)aDecoder { return [self yy_modelInitWithCoder:aDecoder]; }
- (id)copyWithZone:(NSZone *)zone { return [self yy_modelCopy]; }
- (NSUInteger)hash { return [self yy_modelHash]; }
- (BOOL)isEqual:(id)object { return [self yy_modelIsEqual:object]; }
@end

在一个对象的实现中,调用 YYModel 对应的方法,即可实现 NSCoding/NSCopying/hash/equal 协议。YYModel 会自动处理所有有效的 property。

最后

YYModel 的设计目标是高性能和高容错性,虽然功能并不如 Mantle 等项目丰富,但是性能却是远远高于它们。上面所有的方法内部都经过仔细检查,能确保每个属性类型的正确性,避免了可能的崩溃问题。

关于 YYModel 的性能和内部实现机制,来看下一篇文章:iOS JSON 模型转换库的评测。

你可能感兴趣的:(iOS)