加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

objective-c – 核心数据查找或创建最有效的方式

发布时间:2020-12-16 03:41:18 所属栏目:百科 来源:网络整理
导读:我有大约10000个实体“消息”的对象.当我添加一个新的“消息”时,我想先看看它是否存在 – 如果它只是更新它的数据,但是如果不创建它. 现在,“find-or-create”算法通过将所有Message对象的objectID保存在一个数组中,然后过滤并使用existingObjectWithID获取
我有大约10000个实体“消息”的对象.当我添加一个新的“消息”时,我想先看看它是否存在 – 如果它只是更新它的数据,但是如果不创建它.

现在,“find-or-create”算法通过将所有Message对象的objectID保存在一个数组中,然后过滤并使用existingObjectWithID获取消息:error:

这样可以正常工作,但是在我使用existingObjectWithID获取“消息”的情况下,然后尝试通过设置“消息”对象的属性并调用保存来设置和保存属性:在上下文中,它不正确保存.有人遇到这样的问题吗?

有没有更有效的方法来创建或创建算法?

解决方法

首先,消息是CoreData实体的“坏”名称,因为苹果内部使用它,并在后续的开发中引起问题.
你可以阅读更多关于它 HERE

我注意到所有建议的解决方案都使用数组或提取请求.
你可能想考虑一个基于字典的解决方案…

在单个线程/上下文应用程序中,通过将新插入的对象(类型为Message)添加到高速缓存(字典)中,并使用现有的对象标识和键映射预先填充高速缓存,可以实现这一任务.

考虑这个界面:

@interface UniquenessEnforcer : NSObject

@property (readonly,nonatomic,strong) NSPersistentStoreCoordinator* coordinator;
@property (readonly,strong) NSEntityDescription* entity;
@property (readonly,strong) NSString* keyProperty;
@property (nonatomic,readonly,strong) NSError* error;

- (instancetype) initWithEntity:(NSEntityDescription *)entity
                    keyProperty:(NSString*)keyProperty
                    coordinator:(NSPersistentStoreCoordinator*)coordinator;

- (NSArray*) existingObjectIDsForKeys:(NSArray*)keys;
- (void) unregisterKeys:(NSArray*)keys;
- (void) registerObjects:(NSArray*)objects;//objects must have permanent objectIDs
- (NSArray*) findOrCreate:(NSArray*)keys
                  context:(NSManagedObjectContext*)context
                    error:(NSError* __autoreleasing*)error;
@end

流:

1)在应用程序启动时,分配一个“唯一执行者”并填充缓存:

//private method of uniqueness enforcer
- (void) populateCache
{
    NSManagedObjectContext* context = [[NSManagedObjectContext alloc] init];
    context.persistentStoreCoordinator = self.coordinator;

    NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:self.entity.name];
    [r setResultType:NSDictionaryResultType];

    NSExpressionDescription* objectIdDesc = [NSExpressionDescription new];
    objectIdDesc.name = @"objectID";
    objectIdDesc.expression = [NSExpression expressionForEvaluatedObject];
    objectIdDesc.expressionResultType = NSObjectIDAttributeType;

    r.propertiesToFetch = @[self.keyProperty,objectIdDesc];

    NSError* error = nil;

    NSArray* results = [context executeFetchRequest:r error:&error];
    self.error = error;
    if (results) {
        for (NSDictionary* dict in results) {
            _cache[dict[self.keyProperty]] = dict[@"objectID"];
        }
    } else {
        _cache = nil;
    }
}

2)当你需要测试存在时,只需使用:

- (NSArray*) existingObjectIDsForKeys:(NSArray *)keys
{
    return [_cache objectsForKeys:keys notFoundMarker:[NSNull null]];
}

3)当你喜欢实际获取对象并创建缺失的对象时:

- (NSArray*) findOrCreate:(NSArray*)keys
                  context:(NSManagedObjectContext*)context
                    error:(NSError* __autoreleasing*)error
{
    NSMutableArray* fullList = [[NSMutableArray alloc] initWithCapacity:[keys count]];
    NSMutableArray* needFetch = [[NSMutableArray alloc] initWithCapacity:[keys count]];

    NSManagedObject* object = nil;
    for (id<NSCopying> key in keys) {
        NSManagedObjectID* oID = _cache[key];
        if (oID) {
            object = [context objectWithID:oID];
            if ([object isFault]) {
                [needFetch addObject:oID];
            }
        } else {
            object = [NSEntityDescription insertNewObjectForEntityForName:self.entity.name
                                                   inManagedObjectContext:context];
            [object setValue:key forKey:self.keyProperty];
        }
        [fullList addObject:object];
    }

    if ([needFetch count]) {
        NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:self.entity.name];
        r.predicate = [NSPredicate predicateWithFormat:@"SELF IN %@",needFetch];
        if([context executeFetchRequest:r error:error] == nil) {//load the missing faults from store
            fullList = nil;
        }
    }

    return fullList;
}

在这个实现中,您需要自己跟踪对象的删除/创建.
成功保存后,可以使用register / unregister方法(简单实现).
您可以通过挂起上下文“保存”通知并通过相关更改更新缓存来使其更自动化.

多线程的情况要复杂得多(相同的接口,但是在考虑性能的时候,完全不同).
例如,您必须使执行者将新项目(存储)保存到返回请求上下文之前,因为它们不具有永久ID,即使您调用“获取永久ID”,请求上下文可能最终不会保存.
您还需要使用某种排序队列(并行或串行)来访问您的缓存字典.

一些数学:

鉴于:
10K(10 * 1024)独特的键对象
平均密钥长度为256 [字节]
objectID长度为128 [字节]
我们正在看:
10K *(256 128)=?4 [MB]的存储器

这可能是一个很高的估计,但你应该考虑到这一点…

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读