cocoa - 如何让 Core Data 使用我自己的 NSManagedObjectID URI 方案?

标签 cocoa cocoa-touch core-data

我正在编写一个连接到数据库以获取数据的应用程序。由于获取成本高昂且数据通常不会改变,因此我使用 CoreData 来缓存结果,以便可以进行快速的本地查询。

从数据库中,对于每种类型,都有一个保证唯一的字符串属性。事实上,数据库有一个 URI 方案,它是每个项目的唯一地址。

URL 方案非常基本,大致如下:

ngaobject://<server_license_id>/<type>/<identifier>

我也希望能够在 CoreData 中使用它。我创建了一种从 CoreData 存储中获取单个项目的方法:

-(NSFetchRequest*)fetchRequestForType:(NSString*)typeName identifier:(NSString*)identifier
{
    NSFetchRequest * fetchRequest = [self fetchRequestForType:typeName];

    [fetchRequest setFetchLimit:1];

    NSString * identifierProperty = [self identifierPropertyNameForObjectType:typeName];
    NSPredicate * predicate = [NSPredicate predicateWithFormat:@"%K == %@", identifierProperty, identifier];
    [fetchRequest setPredicate:predicate];

    return fetchRequest;
}

-(NGAObject*)objectWithType:(NSString*)typeName
identifier:(NSString*)identifier
    {
        // First try to retrieve it from the cache

    NSAssert1( (identifier != nil), @"Request to create nil-name object of type %@", typeName );

    NSFetchRequest * fetchRequest = [self fetchRequestForType:typeName identifier:identifier];

    if ( !fetchRequest )
        return nil;

    NSError * error = nil;
    NSArray * fetchResults = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];

    if ( !fetchResults )
    {
        NSLog(@"%@", error);
        [NSApp presentError:error];
        return nil;
    }

    if ( [fetchResults count] )
        return [fetchResults objectAtIndex:0];

    return nil;
}

当我从服务器检索一个项目时,我想首先在缓存中获取对它的引用,如果存在,则更新它。如果不是,请创建一个新的。

由于我要从服务器取回数千个对象,因此对我知道其唯一 ID 的单个对象执行提取会使我的计算机变得缓慢。

相反,我正在做的是预加载某个类型的所有对象,然后创建一个标识符->对象的字典,然后通过运行该字典来处理该类型的数千个对象。这工作得很好,但是很尴尬。

我是否可以编写一个采用类型/标识符组合并从 CoreData 获取单个对象而无需执行冗长的获取请求的方法?

如果我能让 CoreData 使用我自己的 URI 规范,似乎就有一个解决方案。然后我可以在持久存储协调器上调用 -(NSManagedObjectID*)managedObjectIDForURIRepresentation:(NSURL*)url

所以,问题是,如何让 CoreData 使用我的 URI 方案?如何让 CoreData 使用我自己的唯一标识符?

最佳答案

您无法让 Core Data 使用自定义 URI 方案。 URI 方案被硬编码到 Core Data 中,以便可以对 URI 进行解码以定位特定硬件上的特定应用程序中的特定存储中的特定数据。如果 URI 是可定制的,那么该系统就会崩溃。

单独获取对象会害死你。相反,您需要批量获取其 customID 与服务器提供的那些匹配的所有对象。最简单的方法是使用 IN 谓词运算符:

NSArray *customIDs=//... array of customIDs provided by server
NSPredicate *p;
p=[NSPredicate predicateWithFormat: @"customIdAtrribute IN %@", customIDs];

这将返回您可以忽略的所有现有对象。

或者,你可以

  1. 通过将提取的 propertiesToFetch 设置为 customID 属性,仅提取 customID 属性。
  2. 将获取结果类型设置为字典。
  3. 使用上面的谓词。
  4. 您将获得一组返回的单键字典,其中每个值都是 customID。
  5. 将字典转换为值数组,例如 cachedIDs
  6. 将上面的 customID 转换为可变数组。
  7. 使用谓词 @"NOT (SELF IN %@)", cachedIDs"过滤 customIDs 数组
  8. 过滤后的 customIDs 数组现在将仅包含未缓存在核心数据中的 customID 值。
  9. 您只能为新 ID 创建托管对象。

(如果您不熟悉过滤谓词,这就是您使用过滤谓词的方法。)

NSMutableArray *f=[NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4",@"5",@"6",nil];
NSArray *g=[NSArray arrayWithObjects:@"5",@"6",nil];
[f filterUsingPredicate:[NSPredicate predicateWithFormat:@"NOT (SELF IN %@)",g]];
NSLog(@"f=%@",f);

...输出:

f=(
    1,
    2,
    3,
    4
)

关于cocoa - 如何让 Core Data 使用我自己的 NSManagedObjectID URI 方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3601992/

相关文章:

cocoa - 更改比例时如何保持 NSScrollView 中的滚动位置?

ios - 在 Core Data 中使用 Cascade 删除关系对象

cocoa - Finder 与应用程序沙箱同步关闭无法正常工作

swift - 使用 NSKeyedUnarchiver 取消存档时捕获异常

ios - 在一周的某些天重复 UILocalNotification

iphone - CALayer 阴影和半透明 UINavigationBars

ios - 集成和核心数据轻迁移

ios - 在太多关系 child 中无法访问逆

macos - 通过拖动背景来移动窗口(movableByWindowBackground)

macos - 在 SpriteKit 中使用 NSButton