【问题标题】:Adding unique objects to Core Data向 Core Data 添加唯一对象
【发布时间】:2009-08-05 22:34:48
【问题描述】:

我正在开发一个从数据库中获取大量对象的 iPhone 应用程序。我想使用 Core Data 来存储这些,但我的关系有问题。

一个详细信息包含任意数量的 POI(兴趣点)。当我从服务器获取一组 POI 时,它们包含一个详细 ID。为了将 POI 与 Detail 关联(按 ID),我的过程如下: 在 ManagedObjectContext 中查询 detailID。 如果该详细信息存在,请将 poi 添加到其中。 如果没有,请创建详细信息(它还有其他将延迟填充的属性)。

问题在于性能。由于涉及到多个关系,对 Core Data 执行持续查询很慢,以至于添加 150 个 POI 的列表需要一分钟。

在我的旧模型中,在 Core Data(各种 NSDictionary 缓存对象)之前,这个过程非常快(在字典中查找一个键,如果它不存在则创建它)

我的关系不止这一个,但几乎每个人都必须做这个检查(有些是多对多的,而且他们有一个真正的问题)。

有没有人对我可以如何提供帮助有任何建议?我可以执行更少的查询(通过搜索多个不同的 ID),但我不确定这会有多大帮助。

一些代码:

        POI *poi = [NSEntityDescription
                insertNewObjectForEntityForName:@"POI"
                inManagedObjectContext:[(AppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext]];

    poi.POIid = [attributeDict objectForKey:kAttributeID];
    poi.detailId = [attributeDict objectForKey:kAttributeDetailID];
    Detail *detail = [self findDetailForID:poi.POIid];
    if(detail == nil)
    {
        detail = [NSEntityDescription
                    insertNewObjectForEntityForName:@"Detail"
                    inManagedObjectContext:[(AppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext]];
        detail.title = poi.POIid;
        detail.subtitle = @"";
        detail.detailType = [attributeDict objectForKey:kAttributeType];
    }





-(Detail*)findDetailForID:(NSString*)detailID {
NSManagedObjectContext *moc = [[UIApplication sharedApplication].delegate managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription
                                          entityForName:@"Detail" inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];

NSPredicate *predicate = [NSPredicate predicateWithFormat:
                          @"detailid == %@", detailID];
[request setPredicate:predicate];
NSLog(@"%@", [predicate description]);

NSError *error;
NSArray *array = [moc executeFetchRequest:request error:&error];
if (array == nil || [array count] != 1)
{
        // Deal with error...
    return nil;
}
return [array objectAtIndex:0];
}

【问题讨论】:

  • 更详细地解释您的对象,并发布您使用的一些代码。几乎 100% 可能有一种方法可以更快地完成您已经在做的事情。

标签: objective-c iphone core-data


【解决方案1】:

查看 Norman 在他的回答中链接到的 Xcode Core Data Programming Guide 中标题为“Core Data Performance”的页面上标题为“Batch Faulting”的部分。

仅获取那些 id 为 IN 的 managedObjects 集合(NSSetNSArrayNSDictionary)服务器返回的对象的 id 可能更有效。

NSSet *oids = [[NSSet alloc] initWithObjects:@"oid1", @"oid2", ..., nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"oid IN %@", oids];
[oids release];

更新:我将此技巧用于acani usersView 的解决方案。基本上,在下载JSON response of users 之后,iPhone 使用popular open source JSON framework 将响应解析为NSArrayNSDictionary 对象,每个对象代表一个用户。然后,它会生成一个NSArray 的 uid,并在 Core Data 上进行批量提取,以查看它们中的任何一个是否已经存在于 iPhone 上。如果没有,它会插入它。如果是这样,它只更新确实存在的那些updated 属性比来自服务器的属性旧。

【讨论】:

    【解决方案2】:

    感谢诺曼,让我顺利完成了这一切,他让我走上了正确的道路。我会在这里为其他人发布我的助手类。

    基本上,我的助手类会查找某个 ID 是否存在 NSManagedObject,并可以为某个 ID 创建它。这对我来说执行得足够快,在我的 iPhone 上执行 1,000 次查找/创建操作大约需要 2 秒(我还在那里做了一些其他事情,纯粹的查找/创建可能更快)。

    它通过缓存所有 NSManagedObjects 的字典并检查该缓存而不是执行新的 NSFetchRequest 来做到这一点。

    一些可以帮助进一步加快速度的修改: 1. 仅获取 NSManagedObjects 的选定属性 2. 仅将 NSManagedObject 的标识符属性获取到字典中,而不是整个对象。 在我的性能测试中,单个查询并不是慢的部分(但只有 1,000 个项目,我希望它会很快)。缓慢的部分是项目的创建。

      #import "CoreDataUniquer.h"
    
    
    @implementation CoreDataUniquer
    
        //the identifying property is the field on the NSManagedObject that will be used to look up our custom identifier
    -(id)initWithEntityName:(NSString*)newEntityName andIdentifyingProperty:(NSString*)newIdProp
    {
        self = [super init];
        if (self != nil) {
            entityName = [newEntityName retain];
            identifyingProperty = [newIdProp retain];
        }
        return self;
    }
    
    -(NSManagedObject*)findObjectForID:(NSString*)identifier
    {
        if(identifier == nil)
        {
            return nil;
        }
        if(!objectList)
        {   
            NSManagedObjectContext *moc = [(AppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext];
            NSEntityDescription *entityDescription = [NSEntityDescription
                                                      entityForName:entityName inManagedObjectContext:moc];
            NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
            [request setEntity:entityDescription];
    
            NSError *error;
            NSArray *array = [moc executeFetchRequest:request error:&error];
            objectList = [[NSMutableDictionary dictionary] retain];
            for (NSManagedObject* p in array) {
                NSString* itemId = [p valueForKey:identifyingProperty];
                [objectList setObject:p forKey:itemId];
            }
        }
        NSManagedObject* returnedObject = [objectList objectForKey:identifier];
        return returnedObject;
    }
    -(NSManagedObject*)createObjectForID:(NSString*)identifier
    {
    
        NSManagedObject* returnedObject = [NSEntityDescription
                                           insertNewObjectForEntityForName:entityName
                                           inManagedObjectContext:[(AppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext]];
        [returnedObject setValue:identifier forKey:identifyingProperty];
        [objectList setObject:returnedObject forKey:identifier];
        return returnedObject;
    }
    
    
    - (void) dealloc
    {
        DESTROY(entityName);
        DESTROY(identifyingProperty);
        [super dealloc];
    }
    
    @end
    

    【讨论】:

    • 另外,请确保在您的标识符属性上勾选“索引”选项。
    • 谢谢!请您也发布 .h 文件吗?
    • 您尝试通过检查商店中的所有实体来查找具有属性值的实体。您访问所有这些实体,它将故障状态更改为实际查询。我认为你必须对 NSFetchRequest 使用谓词和限制并执行查询。如果 count > 0,则表示具有属性的实体已存在于持久存储中。之后,您可以访问此请求结果以更新您的实体。
    【解决方案3】:

    此页面提供了一些关于优化性能的帮助: http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles/cdPerformance.html#//apple_ref/doc/uid/TP40003468-SW1

    虽然效率不高,但为什么不使用 NSDictionary 在内存中构建它们呢?将 Core Data 中的所有内容读入 NSDictionary,然后合并您的数据,替换 Core Data 中的所有内容。

    【讨论】:

    • 有趣的想法。然后,每当创建对象时,模式将是 1. 获取相关对象的可能范围,使用键 2 存储在 NSDictionary 中。如果 id 存在,则将关系添加到该对象 3. 如果 id 不存在,则添加新对象字典和核心数据。添加关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    相关资源
    最近更新 更多