对于一对一关系的不可接受的价值类型:property =" user&#34 ;;所需类型=用户;给定type = User;

时间:2016-11-14 21:18:43

标签: ios swift core-data nsmanagedobject nsmanagedobjectcontext

我遇到核心数据的有线问题。使用iOS 10中的Swift3,每次使用

获取或存储数据时,都会获得托管对象上下文
 func getContext () -> NSManagedObjectContext {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    return appDelegate.persistentContainer.viewContext
}

在我的应用中,我有两个实体'用户'和' Ledger'。我想为用户分配分类帐,但用户可以有多个分类帐。因此,我有一个UserTableView,我可以在其中显示用户和UserViewController类,我在其中创建一个用户。我对分类账也一样。在创建分类帐时,我还会得到一个所有用户的列表,我从中选择一个用户,哪个用户应该分配到分类帐,反之亦然。

如上所述保存时,我收到错误

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for to-one relationship: property = "user"; desired type = User; given type = User;

我的数据模型如下: Data Model

非常感谢任何帮助:)

3 个答案:

答案 0 :(得分:6)

我有同样的问题。在我的情况下,当我运行单元测试时发生了这种情况。在这种情况下,内存中同时存在两个核心数据堆栈,一个用于应用程序工具,另一个用于运行单元测试。

解决这个问题的第一个线索是在设置关系属性之前放置一个断言,以确保我设置的对象的实体类型与关系的预期实体类型相同。它们应该是相同的,在我的情况下它们不是。

在我的情况下,我有MatchRequestPlayer有一对一的关系,称为"发起人"。所以我的断言如下:

    let player = try Player.findLocal(for: matchRequest.initiator, in: moc, createIfMissing: true)
    let expectedEntity = self.entity.relationshipsByName["initiator"]!.destinationEntity!
    assert(player!.entity === expectedEntity, "Player returned doesn't have the same entity type")
    self.initiator = player

上述断言失败,我怀疑它类似于Core Data使用的导致参数异常的断言。

检查Player.entity()时,它将返回导致失败的同一实体实例。

我认为问题的根源在于Core Data正在为核心数据堆栈中错误共享的实体设置一些静态属性。当从一个堆栈调用而不调用另一个堆栈时,调用MyManagedObject.entity()将正常工作。

因此,要解决这个问题,当我创建我的Player对象以进入关系时,我会使用较旧的NSEntityDescription.insertNewObject(...) API而不是较新的MyManagedObject(context:)构造函数来获取实体。这可确保将正确的实体用于给定的托管对象上下文。

所以,回顾一下:

// SOMETIMES FAILS if you have more than one core data stack:
result = Player(context: managedObjectContext)

// ALWAYS WORKS:
result = NSEntityDescription.insertNewObject(forEntityName: "Player", into: managedObjectContext) as? Player

答案 1 :(得分:0)

我遇到了同样的问题,但是我非常确定自己没有像以前的回答那样有2个核心数据栈。

最后,我意识到我已经使用if ( args.Button == 2) // right button clicked { // Code to display your dialogbox } 关键字初始化了对$headers ='From: "intranet "<administratif@groupname.com>'."\n"; $headers .='Reply-To: administratif@groupname.com'."\n"; $headers .='Content-Type: text/plain; charset=utf-8 '."\n"; $headers .='Content-Transfer-Encoding: 8bit'; mail($to, $subject, $message, $headers); 的引用以及视图上下文和背景上下文。我还有一堆代码在后台线程中进行了一些繁重的工作,并使用上述堆栈进行保存。

  

Apple的文档说:“如果标有lazy修饰符的属性是   同时被多个线程访问,并且该属性没有   尚未初始化,无法保证该属性将被   仅初始化一次。”

因此,这种不幸的情况是解决此错误的另一种方法。解决方案:在执行大量后台/前台线程工作时,请确保不要NSStoreCoordinator专门在您的Core Data Stack中进行任何操作。

我希望它将来对某人有帮助。对于未来的开发人员,如果您在这里:祝你好运。

答案 2 :(得分:0)

我遇到了同样的问题。我认为@Chris已明确给出了原因。执行测试时,内存中有多个实例。

解决方案是将NSPersistentContainer的初始部分移到setUpWithErrortearDownWithError中。

在下面的示例中,CoreDataManager处理init中的NSPersistentContainer

代码如下:

之前

class FooTests: XCTestCase {
    var manager: CoreDataManager = CoreDataManager()
}

之后

 class FooTests: XCTestCase {

        var manager: CoreDataManager?

        override func setUpWithError() throws {
             manager = CoreDataManager(inMemory: true)
        }

        override func tearDownWithError() throws {
             manager = nil
        }

    }