在插入新的子对象时,父子对象传递与多级的一对多关系。 IOS核心数据

Posted

技术标签:

【中文标题】在插入新的子对象时,父子对象传递与多级的一对多关系。 IOS核心数据【英文标题】:Parent to child object pass for one to many relationship with multilevel while inserting new child object . Ios Core data 【发布时间】:2015-05-18 12:56:00 【问题描述】:

我在后台保存 coredata 时遇到问题。我正在实施以下模型:

MasterManagedObject(NSPrivateQueueConcurrencyType 类型) MainManagedObjectContext(类型为 NSMainQueueConcurrencyType & 是 MasterManagedObject 的子级) TemporaryManagedObjectContext(类型为 NSPrivateQueueConcurrencyType 并且是 MainManagedObjectContext 的子级)

代码是:

- (NSManagedObjectContext *)masterManagedObjectContext 
    if (_masterManagedObjectContext) 
        return _masterManagedObjectContext;
    
    NSPersistentStoreCoordinator *coordinator = [self storeCoordinator];
    if (coordinator != nil) 
        dime(@"Here in master context");
        _masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [_masterManagedObjectContext setPersistentStoreCoordinator:coordinator];
    
    return _masterManagedObjectContext;


- (NSManagedObjectContext *)mainManagedObjectContext 
    if (_mainManagedObjectContext) 
        return _mainManagedObjectContext;
    

    _mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [_mainManagedObjectContext setParentContext:self.masterManagedObjectContext];
    return _mainManagedObjectContext;


+ (NSManagedObjectContext *)temporaryWorkerContext 

    NSManagedObjectContext *tempMOContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    tempMOContext.parentContext = [[DDPersist manager] mainManagedObjectContext];
    return tempMOContext;

保存上下文:

+ (void)saveTempContext:(NSManagedObjectContext *)context 
    NSError *error;
    [context save:&error];
    if (!error) 
        [[DDPersist manager] saveMainContext];
        dime(@"Temp Context Saved");
     else 
        dime(@"Temp Context Error  = %@",error);
    


- (void)saveMainContext 
    [[[DDPersist manager] mainManagedObjectContext] performBlock:^
        NSError *error = nil;
        [[[DDPersist manager] mainManagedObjectContext] save:&error];
        if(!error)
            //Write to disk after saving on the main UI context
            [[DDPersist manager] saveMasterContext];
            dime(@"main Context Saved");
         else 
            dime(@"Main Context Error  = %@",error);
        
    ];


- (void)saveMasterContext 
    [self.masterManagedObjectContext performBlock:^
        NSError *error = nil;
        [self.masterManagedObjectContext save:&error];
        if(error)
            dime(@"Master Context Saved");
         else 
            dime(@"Master Context Error  %@", error);
            if([NSThread isMainThread]) 
                dime(@"Master Context Error NOT ON BACKGROUND CONTEXT! WILL AUTOMATICALLY PERSIST ON MAIN CTX!");
            
        
    ];

我正在使用上面在后台线程中创建新的 spaceChecklistItems 对象,如下所示: //space 是spaceCheckListItem 的父级,具有一对多的关系。

                    __block NSManagedObjectID *spaceObjectID = [space objectID];
                    //Background thread starts here 
                    [DDPersist performTaskOnBackgroundCtxWithParentChildScheme:^(NSManagedObjectContext *bgCtx) 

                        Space *localSpace = (Space*)[bgCtx objectWithID:spaceObjectID];

                        for(NSDictionary * spaceChecklistItemDict in spaceChecklistItems) 
                            SpaceChecklistItem * spaceChecklistItem = [SpaceChecklistItemService importSpaceChecklistItem:spaceChecklistItemDict space:localSpace];
                            NSAssert(spaceChecklistItem, @"invalid SpaceChecklistItem at import!");
                            if(!spaceChecklistItem) continue;

                        
                        [bgCtx obtainPermanentIDsForObjects:bgCtx.insertedObjects.allObjects error:nil];

                        [DDPersist saveTempContext:bgCtx];
                    ];

后台上下文中使用的方法(importSpaceChecklistItem)如下:

+ (SpaceChecklistItem*)importSpaceChecklistItem:(NSDictionary*)itemDict space:(Space*)space 

NSNumber *spaceChecklistItemId  = [itemDict objectForKey:@"id"];

NSString * inspectionStatus ;
if ([itemDict objectForKey:@"inspectionStatus"]) 
    inspectionStatus = [itemDict objectForKey:@"inspectionStatus"];
 else 
    inspectionStatus = @"UNDECIDED";


NSString * notes = [itemDict objectForKey:@"notes"];
MOC * ctx = space.managedObjectContext;

SpaceChecklistItem * spaceChecklistItem = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([SpaceChecklistItem class])
                                                                        inManagedObjectContext:ctx];


spaceChecklistItem.spaceChecklistItemId = spaceChecklistItemId;
spaceChecklistItem.space = space;// This is the relationship saving & not working.
spaceChecklistItem.inspectionStatus = inspectionStatus;
spaceChecklistItem.notes=notes;
spaceChecklistItem.sync = @NO;    
return spaceChecklistItem;

主要问题是性能问题。我想从上面加速循环:for(NSDictionary * spaceChecklistItemDict in spaceChecklistItems)。并且想把所有的处理变成后台。这个 for 循环可能包含超过 50000 次迭代。这通常需要时间(大约 3 分钟)才能保存到 coredata 中。如果我使用单线程并在 main 的单线程子项(不是主上下文)中保持 for 循环,则数据正在保存。但是这种一对多的关系给我带来了问题,我为此苦苦挣扎了很长时间。

我阅读了许多 *** 问题和许多其他文章。但不能解决这个问题。任何帮助将不胜感激。

【问题讨论】:

您似乎没有在导入方法中创建任何spaceChecklistItem @Mundi ,对不起,我在从实际代码复制到 *** 上的此处并删除额外代码时错过了该行。我现在更新了我的代码。 【参考方案1】:

您是否运行过 Instruments?

运行时间分析器并查看花费最多的时间。

将该跟踪发布到您的问题中,以便其他人也可以看到它。

【讨论】:

我可以补充,没问题。但是我目前在保存上下文时遇到了问题。仪器是完全不同的东西。如果我能以某种方式解决这个上下文保存问题,那么我认为它会解决所有问题。我在那里遇到了关系错误。 Instruments 是解决性能问题的首选工具。这是你第一个去看看为什么有些东西很慢的地方。这个保存问题,如果它没有产生错误,需要在 Instruments 中查看。否则你只是在浪费时间猜测和假设。这甚至可能不是核心数据问题,可能是线程问题,可能是数据问题。在时间分析器下运行它之前,你不会知道。说真的,这是第一步。

以上是关于在插入新的子对象时,父子对象传递与多级的一对多关系。 IOS核心数据的主要内容,如果未能解决你的问题,请参考以下文章

Nhibernate一对多关系复合键问题

没有关系的房间中的一对多关系

如果同时保存的两个实体父子实体映射为一对多关系,则抛出 id not found 父类异常

如何将 .NET 对象集合(父子)层次结构传递给 SQL Server 存储过程

QT之对象父子关系

iOS核心数据如何使用NSPredicate根据一对多的子属性查找父对象?