2016-07-12 15 views
0

Jsonとは異なるテーブルにデータをインポートする必要のあるアプリケーションを開発しています。私はすべてのテーブルに汎用関数を使用します。問題は、テーブルに多数のレコードがある場合、インポートが非常に遅いことです。コアデータのインポートが非常に遅い

parseJSON機能:

-(void)parseJSON:(NSArray *)json entity:(NSString *)entityName{ 

[json enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
    NSArray *primaryKeyNameJSON = [self getPrimaryKeyNameForEntityInJSON:entityName]; 
    NSArray *primaryKey = [obj objectsForKeys:primaryKeyNameJSON notFoundMarker:@""]; 
    NSArray *primaryKeyName = [self getPrimaryKeyNameForEntity:entityName]; 

    NSDictionary *primaryKeysAndValues = [NSDictionary dictionaryWithObjects:primaryKey forKeys:primaryKeyName]; 

    NSManagedObject *managedObj = [self getManagedObjectForEntity:entityName primaryKey:primaryKeysAndValues jsonEntity:entityName json:obj]; 

    NSDictionary *allAttributes = [[managedObj entity] attributesByName]; 
    NSArray *attributesKeys = [allAttributes allKeys]; 

    NSDictionary *allRelationships = [[managedObj entity] relationshipsByName]; 
    NSArray *relationshipsKeys = [allRelationships allKeys]; 

    NSArray *keys = [obj allKeys]; 
    for (NSString *jsonKey in keys) { 

     NSString *dbKey = [self getDBKeyForJSONKey:jsonKey entity:entityName]; 
     if ([attributesKeys containsObject:dbKey]) { 
      //Attribute 
      NSAttributeDescription *oneAttribute = [allAttributes objectForKey:dbKey]; 
      if ([oneAttribute attributeType] == NSDateAttributeType){ 
       [managedObj setValue:[[self dateFormatterJSon] dateFromString:[obj objectForKey:jsonKey]] forKey:dbKey]; 
      }else if ([oneAttribute attributeType] == NSInteger32AttributeType || [oneAttribute attributeType] == NSFloatAttributeType){ 
       [managedObj setValue:[[self numberFormatterJSon] numberFromString:[obj objectForKey:jsonKey]] forKey:dbKey]; 
      }else if ([oneAttribute attributeType] == NSStringAttributeType) 
       [managedObj setValue:[obj objectForKey:jsonKey] forKey:dbKey]; 
      else if ([oneAttribute attributeType] == NSBooleanAttributeType) { 
       if ([[obj objectForKey:jsonKey] isEqual: @"-1"] || [[obj objectForKey:jsonKey] isEqual: @"1"]){ 
        [managedObj setValue:[NSNumber numberWithBool:YES] forKey:dbKey]; 
       }else{ 
        [managedObj setValue:[NSNumber numberWithBool:NO] forKey:dbKey]; 
       } 
      } 
     } 
     else if ([relationshipsKeys containsObject:dbKey]) { 
      //Relationship 
      NSRelationshipDescription *oneRelationship = [allRelationships objectForKey:dbKey]; 
      NSString *destRelationshipEntityName = [[oneRelationship destinationEntity] name]; 

      NSArray *destRelationshipPrimaryKeyName = [self getPrimaryKeyNameForEntity:destRelationshipEntityName]; 
      NSArray *destRelationshipPrimaryKeyValues = [[NSArray alloc] init]; 
      destRelationshipPrimaryKeyValues = [obj objectsForKeys:[self getPrimaryKeyNameForEntity:destRelationshipEntityName inJSONEntity:entityName attrName:jsonKey] notFoundMarker:@""]; 
      NSDictionary *destRelPrimaryKeysAndValues = [NSDictionary dictionaryWithObjects:destRelationshipPrimaryKeyValues forKeys:destRelationshipPrimaryKeyName]; 

      NSManagedObject *destManagedObject = [self getManagedObjectForEntity:destRelationshipEntityName primaryKey:destRelPrimaryKeysAndValues jsonEntity:entityName json:obj]; 

      [managedObj setValue:destManagedObject forKey:dbKey]; 
    } 
}]; 
} 

getManagedObjectForEntity機能(ここでは、我々はデータベースで管理オブジェクトを探し、存在しない場合は、それを作成します):

-(NSManagedObject *)getManagedObjectForEntity:(NSString *)entityName primaryKey:(NSDictionary *)key jsonEntity:(NSString *)jsonEntity json:(NSDictionary *)json{ 

NSEntityDescription *entityDescription = [NSEntityDescription entityForName:entityName inManagedObjectContext:context]; 
NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
[request setEntity:entityDescription]; 
NSArray *primaryKeyName = [key allKeys]; 
NSMutableArray *subpredicates = [NSMutableArray array]; 
NSError *error = nil; 
NSArray *managedObjectArray = [[NSArray alloc] init]; 
for (NSString *k in primaryKeyName) { 
    NSPredicate *predicate; 
    NSString *value = [key objectForKey:k]; 
    predicate = [NSPredicate predicateWithFormat:@"(%K == %@)",k,value]; 

    [subpredicates addObject:predicate]; 
} 
NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates]; 

[request setPredicate:predicate]; 

NSError *error = nil; 
managedObjectArray = [context executeFetchRequest:request error:&error]; 

if (managedObjectArray == nil) 
{ 
    // Deal with error... 
} 


if ([managedObjectArray count] > 0) 
    return [managedObjectArray firstObject]; //Object exists 

//If object is not found lets create it 

NSManagedObject *managedObject = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; 

NSDictionary *allAttributes = [entityDescription attributesByName]; 
NSDictionary *allRelationships = [entityDescription relationshipsByName]; 

NSArray *allAttributesName = [allAttributes allKeys]; 

for (NSString *k in primaryKeyName) { 
    if ([allAttributesName containsObject:k]) { 
     //Key is an attribute 
     [managedObject setValue:[key objectForKey:k] forKey:k]; 
    } 
    else { 

     //Key is a relationship 
     NSString *relationshipKey = [[k componentsSeparatedByString:@"."] firstObject]; 
     NSRelationshipDescription *oneRelationship = [allRelationships objectForKey:relationshipKey]; 

     NSString *destEntityName = [[oneRelationship destinationEntity] name]; 
     NSArray *destEntityPrimaryKey = [self getPrimaryKeyNameForEntity:destEntityName]; 

     NSArray *destEntityPrimaryKeyValues = [json objectsForKeys:[self getPrimaryKeyNameForEntity:destEntityName inJSONEntity:jsonEntity attrName:relationshipKey] notFoundMarker:@""]; 

     NSManagedObject *destManagedObj = [self getManagedObjectForEntity:destEntityName primaryKey:[NSDictionary dictionaryWithObjects:destEntityPrimaryKeyValues forKeys:destEntityPrimaryKey] jsonEntity:jsonEntity json:json]; 

     [managedObject setValue:destManagedObj forKey:relationshipKey]; 
    } 
} 

return managedObject; 
} 

最終的に私は、[コンテキストを使用保存:&エラー]は、すべてのJSONデータをインポートしたときに機能します。

私は配列に各テーブルを保存し、配列に管理対象オブジェクトを探してみましたが、各テーブルのデータが大量になるとメモリの問題が発生します。 すべてのデータをより高速にインポートする方法はありますか? ありがとう

答えて

1

パターンは常に高価になります。しかし、あなたのデザインはそれぞれ個のディスクに当たっています。レコードです。それは無駄であり、おそらくあなたの遅さの中核です。

iOS 8またはそれ以前のバージョンを使用している場合は、KVCを使用してすべてのプライマリキーを一度に取得し、既存のレコードを一度に(または少なくともNSManagedObjectID)フェッチする必要があります。挿入または更新を行います。

あなたはiOSの9以降を使用している場合、あなたは(あなたはSQLiteのを使用していると仮定して)永続ストアに制約として、あなたの主キーを設定してからちょうどすべてのレコードを挿入し、コアデータをさせることができますよう、それはさらに簡単です挿入と更新の問題を解決します。

メモリの圧迫として、インポート中にジョブを中断して数回保存したいと思う可能性があります。保存するたびに、-resetを呼び出してメモリからオブジェクトをドロップするように要求することができます。それはあなたが圧力を下げるのを助けます。

最後に、Instrumentsを使用してください。私があなたに与えた一般的なアドバイスは役に立ちますが、タイムプロファイラを使用してコードのホットスポットを探してインポートを微調整することができます。

+0

お返事ありがとうございます。はい、私はIOS 9とSQLiteを使用しています。すべての主キーをxcodeの永続ストアの制約として設定するオプションがあるかどうか知っていますか? –

+0

はい、データモデルでは、プライマリキーを反映するように各エンティティに制約を設定できます。 –

+0

リレーションシップを一意の制約として使用すると問題が発生します.xcodeはコンパイルできません。エラー: "cdtoolはコンパイルできません"。なぜなのかご存知ですか? –

関連する問題