我正在尝试使用从单独的上下文收集的对象ID数组来执行提取以从上下文中检索托管对象.但是,fetch返回一个空数组.

从“核心数据编程指南”的“检索特定对象”部分
link:

If your application uses multiple contexts and you want to test whether an object has been deleted from a persistent store,you can create a fetch request with a predicate of the form self == %@. The object you pass in as the variable can be either a managed object or a managed object ID…”

If you need to test for the existence of several objects,it is more efficient to use the IN operator than it is to execute multiple fetches for individual objects,for example:

nspredicate *predicate = [nspredicate predicateWithFormat:@”self IN %@”,
arrayOfManagedobjectIDs];

虽然这是关于测试对象删除,但我假设如果没有删除对象,那么结果数组不为空,并且将包含实际的NSManagedobjects.但是,当我执行此代码时:

- (NSArray *)managedobjectsOfEntityName:(Nsstring *)entityName fromObjectIDs:(NSArray *)objectIDs managedobjectContext:(NSManagedobjectContext *)managedobjectContext
{
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];
    request.predicate = [nspredicate predicateWithFormat:@"self IN %@",objectIDs];

    __autoreleasing NSError *error = nil;

    NSManagedobjectID *testID = objectIDs[0];
    NSManagedobject *obj = [managedobjectContext existingObjectWithID:testID error:&error];
    if (!obj)
    {
        NSLog(@"Unable to perform fetch. Error: %@",error);
    }

    error = nil;
    NSArray *results = [managedobjectContext executeFetchRequest:request error:&error];
    if (!results)
    {
        NSLog(@"Unable to perform fetch. Error: %@",error);
    }

    return results;
}

结果数组是非零和空的,而obj已正确填充.

我已经添加了对existingObjectWithID的显式调用:作为完整性检查,它返回预期的对象,没有错误.

这是相关变量的调试器输出:

(lldb) po entityName
Foo

(lldb) po objectIDs
<__NSArrayI 0x1170d4950>(
0xd0000000055c0082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p343>,0xd000000008e80082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p570>,0xd000000008840082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p545>,0xd000000006040082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p385>,0xd000000007740082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p477>,0xd000000008280082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p522>,0xd000000008e40082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p569>
)

(lldb) po request
<NSFetchRequest: 0x10f338840> (entity: Foo; predicate: (SELF IN {
0xd0000000055c0082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p343>,0xd000000008e40082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p569>});
sortDescriptors: ((null)); type: NSManagedobjectResultType; )

(lldb) po request.predicate
SELF IN {
0xd0000000055c0082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p343>,0xd000000008e40082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p569>}

(lldb) po testID
0xd0000000055c0082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p343>

(lldb) p testID.istemporaryID
(bool) $7 = false

(lldb) p obj
(NSManagedobject *) $9 = 0x000000010f338630

(lldb) po results
<__NSArrayI 0x10f205c70>(

)

(lldb) po testID.entity
 nil

testID上的nil实体很奇怪,但我不确定它是“坏”.

所以,我显然不知道为什么获取回来是空的.实体名称正确,fetch和谓词看起来很好,对象在上下文中,但结果仍为零.

附加背景:

从本质上讲,更大的图片是我有一个后台操作,它使用自己的托管对象上下文(MOC)来执行一些工作.主要队列需要完成该工作的结果,因此我将工作产生的objectID打包并将其传递给主队列.在主队列上我需要返回实际的托管对象,所以我试图通过objectID从主队列的MOC中获取它们.我意识到我可以在MOC上使用objectWithID:或existingObjectWithID:error:甚至objectRegisteredForID:来获取这些对象,但每个都有自己的特殊问题:

> objectWithID:如果对象不在上下文中,则可能返回一个伪造的对象,如果它在上下文中,它将返回一个错误.
> existingObjectWithID:错误:非常好,因为我们将返回nil(而不是伪造的对象),但它也会返回错误.
> objectRegisteredForID:如果对象不在上下文中,则返回nil.

因此,如果我使用objectWithID:或existingObjectWithID:error:在循环中获取一堆对象,那么可能会在持久存储中跳转以使对象出错,这意味着性能可能会非常糟糕.如果我使用objectRegisteredForID:如果它恰好不在主队列的MOC中,我可能根本不会得到该对象.

因此,我没有尝试迭代数组,而是期望获取请求会限制与persistance存储交互的开销,并一举返回我需要的所有对象.

加成:

顺便说一句,问题确实与@“self IN%@”谓词有关,因为我可以删除该谓词并获取entityName的所有对象而不会出现问题.我还尝试使用@“objectID IN%@”作为具有相同(零)结果的谓词.

解决方法

好的,准备好沿着Core Data兔子洞旅行了吗?

TL; DR

其持久性存储协调器不再在内存中的NSManagedobjectID会丢失其NSEntityDescription(实体),并且不会将(isEqual:返回NO)等同于来自不同持久性存储协调器的NSManagedobjectID,即使它们的URIRepresentation相同也是如此.

沿着兔子洞

甜蜜……我们走了.

请记住,我是在一个单独的线程上从一个单独的托管对象上下文(MOC)收集objectIDs数组?好.但是,我没有提到MOC正在使用自己的持久存储协调器(PSC)(当然,指向同一个文件). PSC和MOC是短暂的,因为一旦工作完成它们就会被自动释放,但是当它们还活着时,我将NSManagedobjectID的实例保存到NSArray中(它被传递给另一个线程).

一旦在单独的线程中收到,NSManagedobjectID就有一个nil实体.这似乎正在发生(有教育的猜测……),因为这些objectID来自的PSC现在不再在内存中,并且NSManagedobjectID必须保持对必须由PSC持有的NSEntityDescription(实体)的一周引用.正如评论者所怀疑的那样,零实体似乎会引起问题……

我无法确定内部结构,但似乎没有实体,NSManagedobjectID不等于具有相同URIRepresentation的另一个NSManagedobjectID.让我说明一下:

在以下代码中:
* objectID是来自持久性存储的NSManagedobjectID *,它不再存储在内存中,其实体属性为nil.
* managedobjectContext是我们当前线程上的MOC(当然)

NSURL *URIRep = objectID.URIRepresentation;
NSManagedobjectID *newObjectID = [managedobjectContext.persistentStoreCoordinator managedobjectIDForURIRepresentation:URIRep];

如果我们在调试器中看到这个…猜猜:

(lldb) p [ojectID isEqual:newObjectID]
(bool) $0 = false

尽管这两个objectID的URIRepresentation必须相同,但对象并不等同.

这几乎可以肯定为什么谓词[nspredicate predicateWithFormat:@“self IN%@”,objectIDs]无法匹配任何对象并导致获取请求返回零对象.

然而,有趣的是,在下面的代码中,testID是来自持久性存储的NSManagedobjectID *,它不再存储在内存中且其实体属性为nil,从MOC中检索对象时没有问题:

NSManagedobject *obj = [managedobjectContext existingObjectWithID:testID error:&error];

解决方法

有两件事我已经验证为解决方法:

>在上下文之间传递NSManagedobjectID时使用相同的持久存储协调器(PSC)(并确保它驻留在内存中).如果这样做,NSManagedobjectIDs永远不会丢失它们的实体,一切都按预期工作.
>不要将NSManagedobjectID从上下文传递到上下文,而是使用它们的URIRepresentation.即,不是传递NSManagedobjectID对象的数组,而是传递表示每个NSManagedobjectID的URIRepresentation的NSURL数组.准备好使用这些objectID执行提取后,使用managedobjectIDForURIRepresentation:消息从当前MOC的PSC获取NSManagedobjectID.

选项1更简单,但可能在并发时序方面存在一些缺点,例如,如果您希望为您的操作设置单独的PSC,则可能限制性太强.

在我(相对有限的)体验中调用managedobjectIDForURIRepresentation:它似乎非常高效,因此将URIRepresentation NSURL转换为NSManagedobjectID似乎不会增加太多开销.

谢谢

感谢您的关注…我希望这有助于清楚地解释问题和解决方法.我当然觉得我通过挖掘所有这些来获得Core Data对象ID和持久性商店协调员的优点徽章.

干杯,

列维

ios – 通过objectID获取NSManagedObjects数组返回空数组的更多相关文章

  1. ios – 重新创建Persistant Store后的核心数据错误

    在我的应用程序中,我能够清除数据库中的所有数据.完成此操作后,将解析捆绑的JSON,然后将其保存到数据库(以便将数据库返回到默认状态).解析和保存此JSON的操作在任何情况下都可正常工作,除非在清除并重新创建持久性存储之后,在这种情况下我得到’NSinvalidargumentexception’,原因:’无法从此NSManagedobjectContext的协调器访问对象的持久存储’.在保存在后

  2. ios – NSArray indexOfObject返回nil

    任何想法为什么我不能得到一个我确定在数组中存在的对象的索引?相反,我没有……

  3. core-data – 错误: – [UIImage _deleteExternalReferenceFromPermanentLocation]无法识别的选择器发送到实例

    当我删除包含图像的托管对象时,在外部记录中存储为可转换值,然后我崩溃并出现此错误:解决方法我在AppleDeveloperforums回答了类似的事情.我猜你在数据建模器中的那个字段上选择了外部存储复选框.有一个bug可以解决.我是这样做的:一旦更新了数据并保存了上下文,任何删除它的尝试都会引发这个“无法识别的选择器”异常.要强制可以响应_deleteExternalReferenceFromPe

  4. ios – 使用watchOS 2在Apple Watch上渲染折线图

    我正在尝试使用watchOS2在AppleWatch上渲染线条/步骤图.与iOS9不同,watchOS2不支持Quartz.它只支持CoreGraphics.我尝试编写一些代码来绘制折线图但我得到一个错误“CGContextRestoreGState:无效的上下文0x0.这是一个严重的错误.这个应用程序,或它使用的库,正在使用无效的上下文,从而有助于整体系统稳定性和可靠性降低.这个通知是礼貌的:请

  5. ios – 多个NSPersistentStoreCoordinator实例可以连接到同一个底层SQLite持久性存储吗?

    我读过的关于在多个线程上使用CoreData的所有内容都讨论了使用共享单个NSPersistentStoreCoordinator的多个NSManagedobjectContext实例.这是理解的,我已经使它在一个应用程序中工作,该应用程序在主线程上使用CoreData来支持UI,并且具有可能需要一段时间才能运行的后台获取操作.问题是NSPersistentStoreCoordinator会对基础

  6. ios – CoreData有序关系 – 使用NSFetchRequest批量取消

    或者,是否存在批量不支持的API,它不是私有的?解决方法目前我有一个解决方案,但不是一个干净的解决方案:我希望按照有序关系中的20个小组进行批量修改.所以,每次我索引一个索引,它的索引除以20,我为接下来的20使用新的NSFetchRequest,并通过调用公共字段名称来解除它们.

  7. ios – 使用SQLite和CoreData进行批量插入

    我有一个使用sqlite作为持久性存储的CoreData模型.在对每条记录进行一些处理之后,我需要插入大量的行.有没有办法将这些命令发送到sqlite我需要加快处理时间,因为它需要几个小时才能完成.任何提示将不胜感激.谢谢解决方法将商店添加到商店协调员时,可以指定编译指示:(改编自PersistentStoreFeatures)我强烈建议您阅读“有效导入数据”.相关文档:NSSQLitePragm

  8. 核心数据 – iOS:由于Xcode 9中的Fetched Indexes,无法编译CoreData模型

    根据发行说明,Xcode9增加了对获取索引的支持:“ThedatamodeleditorpresentsaunifiedinterfaceforCoreData’snewfetchindexesfeatureaswellasitsexistingpropertyindexandentitycompoundindexfeatures.Olderdatamodelsaretranslatedintof

  9. ios – 搜索数组swift中的对象

    我正在尝试使用UISearchController创建搜索功能.但是,我似乎无法使其与我的团队对象一起工作.我首先创建了一个包含id,name和shortname的TeamObject.然后我从一个url中检索teamData,并将TeamObjects添加到一个填充到tableView中的数组中.这个tableView包含一个searchController,它假设过滤数据,但没有任何反应.阵列

  10. 如何在Cocoa中使用Bindings CoreData实现iTunes风格的Source-List?

    让我们说,为了说明,我在Cocoa中编写了一个iTunes克隆应用程序,该应用程序由CoreData支持.为简化起见,假设有两个“部分”,“图书馆”,包括音乐,电影,广播等.第二部分称为“播放列表”,其中包含用户生成的播放列表.所以SourceList本身通常会用NSOutlineView实现,这通常很简单.源列表的“库”部分实际上并不包含用户生成的任何内容,只包含应用程序的“功能”(实质上),其中“播放列表”部分仅包含用户创建的自定义列表.如何用Bindings和CoreData做到这一点?

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部