Mantleソース学習(二)

7491 ワード

MTLJSONSerializing
このプロトコルは、データ変換間のルールを定義します.MTLModelサブクラスを実装する必要があります.
//        key JSON key path       。  :    key             ,     JSON   。
+ (NSDictionary *)JSONKeyPathsByPropertyKey;
//   ,  Model key  NSValueTransformer,       +(NSValueTransformer *)key+JSONTransformerForKey;    。
+ (NSValueTransformer *)JSONTransformerForKey:(NSString *)key;
//           。  
+ (Class)classForParsingJSONDictionary:(NSDictionary *)JSONDictionary;

MTLJSONAdapter
このクラスはデータ変換のコアクラスに属し、変換中にこの関数を手動で呼び出す必要があります.
//        JSON       。
+ (id)modelOfClass:(Class)modelClass fromJSONDictionary:(NSDictionary *)JSONDictionary error:(NSError **)error

この関数の流れ:
  • まずMTLJSOnAdapterオブジェクト
  • を初期化する
    MTLJSONAdapter *adapter = [[self alloc] initWithModelClass:modelClass];
    

    この初期化手法では,主にJSOnkeyPathsByPropertyKeyで定義された正当性をチェックし,keyの対応関係をキャッシュする.次のコードを使用します.
    _valueTransformersByPropertyKey = [self.class valueTransformersForModelClass:modelClass];
    

    キーごとに対応するNSValueTransformer(データ解析変換メソッド)をキャッシュし、辞書にキャッシュします.これらの方法の中にはModelによるものがある.以下のいくつかはModelで実装された変換方式のいくつかの例であり、この関数のフォーマットはkeyのname+JSOnTransformerである.
    // NSURL   
    + (NSValueTransformer *)HTMLURLJSONTransformer {
        return [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName];
    }
    
    //   key-value  。    Map
    + (NSValueTransformer *)stateJSONTransformer {
        return [NSValueTransformer mtl_valueMappingTransformerWithDictionary:@{
                                                                               @"open": @(GHIssueStateOpen),
                                                                               @"closed": @(GHIssueStateClosed)
                                                                               }];
    }
    
    //     (Model   Model),MTLRecursiveUserModel     )
    + (NSValueTransformer *)ownerJSONTransformer {
        return [MTLJSONAdapter dictionaryTransformerWithModelClass:MTLRecursiveUserModel.class];
    }
    
    //      (Model       ),MTLRecursiveUserModel         )
    + (NSValueTransformer *)usersJSONTransformer {
        return [MTLJSONAdapter arrayTransformerWithModelClass:MTLRecursiveUserModel.class];
    }
    
    

    他の一般的なデータ型の変換は、デフォルトのNSValueTransformerを直接使用して行うことができます.Modelで対応する方法を実装する必要はありません.
  • 、次いで、システムはデータのシーケンス化を開始する.このステップでは、
  • というコードを呼び出します.
    [adapter modelFromJSONDictionary:JSONDictionary error:error];
    

    この関数では、まずModelがclassForParsingJSONDictionaryという関数を実現したかどうかを判断し、実現したらJSONをこの関数で返されるデータ型に変換する必要があります.
        if ([self.modelClass respondsToSelector:@selector(classForParsingJSONDictionary:)]) {
            Class class = [self.modelClass classForParsingJSONDictionary:JSONDictionary];
            //       
            if (class == nil) {
                if (error != NULL) {
                    NSDictionary *userInfo = @{
                        NSLocalizedDescriptionKey: NSLocalizedString(@"Could not parse JSON", @""),
                        NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"No model class could be found to parse the JSON dictionary.", @"")
                    };
    
                    *error = [NSError errorWithDomain:MTLJSONAdapterErrorDomain code:MTLJSONAdapterErrorNoClassFound userInfo:userInfo];
                }
    
                return nil;
            }
    
    //                         ,          MTLJSONSerializing  、           MTLJSONAdapter  ,       。     return,         。
            if (class != self.modelClass) {
                NSAssert([class conformsToProtocol:@protocol(MTLJSONSerializing)], @"Class %@ returned from +classForParsingJSONDictionary: does not conform to ", class);
    
                MTLJSONAdapter *otherAdapter = [self JSONAdapterForModelClass:class error:error];
    
                return [otherAdapter modelFromJSONDictionary:JSONDictionary error:error];
            }
        }
        
    

    上記のプロトコルが実装されていない場合.データ解析が始まり、プロセス全体が次のようになります.
    NSMutableDictionary *dictionaryValue = [[NSMutableDictionary alloc] initWithCapacity:JSONDictionary.count];
    
    //      key,     key   
        for (NSString *propertyKey in [self.modelClass propertyKeys]) {
            id JSONKeyPaths = self.JSONKeyPathsByPropertyKey[propertyKey];
    
            if (JSONKeyPaths == nil) continue;
    
            id value;
    
            //   key   value
            if ([JSONKeyPaths isKindOfClass:NSArray.class]) {
                NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
    
                for (NSString *keyPath in JSONKeyPaths) {
                    BOOL success = NO;
                    id value = [JSONDictionary mtl_valueForJSONKeyPath:keyPath success:&success error:error];
    
                    if (!success) return nil;
    
                    if (value != nil) dictionary[keyPath] = value;
                }
    
                value = dictionary;
            } else {
                BOOL success = NO;
                value = [JSONDictionary mtl_valueForJSONKeyPath:JSONKeyPaths success:&success error:error];
    
                if (!success) return nil;
            }
    
            if (value == nil) continue;
    
            @try {
            
            //   key   NSValueTransformer,     NSValueTransformer     
                NSValueTransformer *transformer = self.valueTransformersByPropertyKey[propertyKey];
                if (transformer != nil) {
                    // Map NSNull -> nil for the transformer, and then back for the
                    // dictionary we're going to insert into.
                    if ([value isEqual:NSNull.null]) value = nil;
    
                    if ([transformer respondsToSelector:@selector(transformedValue:success:error:)]) {
                        id errorHandlingTransformer = (id)transformer;
    
                        BOOL success = YES;
                        //            new  MTLJSONAdapter,          ,   value     。
                        value = [errorHandlingTransformer transformedValue:value success:&success error:error];
    
                        if (!success) return nil;
                    } else {
                        //              
                        value = [transformer transformedValue:value];
                    }
    
                    if (value == nil) value = NSNull.null;
                }
    
                dictionaryValue[propertyKey] = value;
            } @catch (NSException *ex) {
                NSLog(@"*** Caught exception %@ parsing JSON key path \"%@\" from: %@", ex, JSONKeyPaths, JSONDictionary);
    
                // Fail fast in Debug builds.
                #if DEBUG
                @throw ex;
                #else
                if (error != NULL) {
                    NSDictionary *userInfo = @{
                        NSLocalizedDescriptionKey: ex.description,
                        NSLocalizedFailureReasonErrorKey: ex.reason,
                        MTLJSONAdapterThrownExceptionErrorKey: ex
                    };
    
                    *error = [NSError errorWithDomain:MTLJSONAdapterErrorDomain code:MTLJSONAdapterErrorExceptionThrown userInfo:userInfo];
                }
    
                return nil;
                #endif
            }
        }
    
    //   KVC value      key, modelWithDictionary MTLModel       ,            (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error;        KVC     ,           。
    
        id model = [self.modelClass modelWithDictionary:dictionaryValue error:error];
    

    以上、JSON---->Modelの手順について詳しく説明しました.他の複雑な機能はしばらく注目されていません