【问题标题】:Swift and CoreData, problems with relationship (NSSet) - [NSSet intersectsSet:]: set argument is not an NSSetSwift 和 CoreData,关系问题 (NSSet) - [NSSet intersectsSet:]: set argument is not an NSSet
【发布时间】:2014-10-07 03:26:24
【问题描述】:

我一直在尝试使用 CoreData 和 Swift 在关系中添加对象。我很茫然,我不明白为什么我的代码不起作用。我正在尝试将“事件”添加到“团队”。我找不到接受的答案(应该有效)和我的代码(无效)之间的区别。

Teams.swift:

import Foundation
import CoreData

class Teams: NSManagedObject {

    @NSManaged var teamName: String
    @NSManaged var matches: NSSet

}

extension Teams {

    func addEventToTeam(event:Event) {
        //self.mutableSetValueForKeyPath("matches").addObject(event)

        var matchez: NSMutableSet

        matchez = self.mutableSetValueForKey("matches")
        matchez.addObject(event)


        //var manyRelation = self.valueForKeyPath("matches") as NSMutableSet
        //manyRelation.addObject(event)
    }

    func getTeamName() -> String {
        return teamName
    }


}

调用代码(从配置视图):

import UIKit
import CoreData

class DetailViewController: UIViewController, NSFetchedResultsControllerDelegate {

    var managedObjectContext: NSManagedObjectContext? = nil

    @IBOutlet weak var detailDescriptionLabel: UILabel!


    var detailItem: AnyObject? {
        didSet {
            // Update the view.
            self.configureView()
        }
    }

    func configureView() {
        // Update the user interface for the detail item.
        if let detail: Event = (self.detailItem as? Event) {
        //if let detail: AnyObject = self.detailItem {

            if let label = self.detailDescriptionLabel {
                label.text = detail.valueForKey("timeStamp").description

                self.insertNewObject(self);
                label.text = String(detail.getNumberOfTeams())

                //detail.getTeams().
                var hej: Array<Teams>
                hej = detail.getTeams()

                label.text = "tjosan"

                for tmpTeam : Teams in hej {
                    label.text = label.text + ", " + tmpTeam.getTeamName()
                }


            }
        }

        if true {


        }


    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.configureView()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    var fetchedResultsController: NSFetchedResultsController {
        if _fetchedResultsController != nil {
            return _fetchedResultsController!
            }

            let fetchRequest = NSFetchRequest()
            // Edit the entity name as appropriate.
            let team = NSEntityDescription.entityForName("Teams", inManagedObjectContext: self.managedObjectContext)
            fetchRequest.entity = team

            // Set the batch size to a suitable number.
            fetchRequest.fetchBatchSize = 20

            // Edit the sort key as appropriate.
            let sortDescriptor = NSSortDescriptor(key: "teamName", ascending: false)
            let sortDescriptors = [sortDescriptor]

            fetchRequest.sortDescriptors = [sortDescriptor]

            // Edit the section name key path and cache name if appropriate.
            // nil for section name key path means "no sections".
            let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: nil, cacheName: "Master")
            aFetchedResultsController.delegate = self
            _fetchedResultsController = aFetchedResultsController

            var error: NSError? = nil
            if !_fetchedResultsController!.performFetch(&error) {
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                //println("Unresolved error \(error), \(error.userInfo)")
                abort()
            }

            return _fetchedResultsController!
    }    
    var _fetchedResultsController: NSFetchedResultsController? = nil



    func insertNewObject(sender: AnyObject) {
        let context = self.fetchedResultsController.managedObjectContext
        let team = self.fetchedResultsController.fetchRequest.entity
        let newManagedObject = NSEntityDescription.insertNewObjectForEntityForName(team.name, inManagedObjectContext: context) as Teams

        // If appropriate, configure the new managed object.
        // Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.
        newManagedObject.setValue("Lagur Namnurk", forKey: "teamName")

        newManagedObject.addEventToTeam(self.detailItem as Event)


        // Save the context.
        var error: NSError? = nil
        if !context.save(&error) {
            // Replace this implementation with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            //println("Unresolved error \(error), \(error.userInfo)")
            abort()
        }
    }



}

错误信息:

2014-08-13 18:38:46.651 Score Calculator 2[10538:829319] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSSet intersectsSet:]: set argument is not an NSSet'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001028a53e5 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x00000001043b8967 objc_exception_throw + 45
    2   CoreFoundation                      0x000000010280fc6c -[NSSet intersectsSet:] + 940
    3   Foundation                          0x0000000102d0c4a6 NSKeyValueWillChangeBySetMutation + 156
    4   Foundation                          0x0000000102c804fa NSKeyValueWillChange + 386
    5   Foundation                          0x0000000102d0c3fb -[NSObject(NSKeyValueObserverNotification) willChangeValueForKey:withSetMutation:usingObjects:] + 310
    6   CoreData                            0x00000001024178d7 -[NSManagedObject(_NSInternalMethods) _includeObject:intoPropertyWithKey:andIndex:] + 551
    7   CoreData                            0x0000000102418294 -[NSManagedObject(_NSInternalMethods) _maintainInverseRelationship:forProperty:forChange:onSet:] + 276
    8   CoreData                            0x0000000102416ef2 -[NSManagedObject(_NSInternalMethods) _didChangeValue:forRelationship:named:withInverse:] + 562
    9   Foundation                          0x0000000102c835d6 NSKeyValueNotifyObserver + 356
    10  Foundation                          0x0000000102c827fd NSKeyValueDidChange + 466
    11  Foundation                          0x0000000102d0c7ee -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:withSetMutation:usingObjects:] + 118
    12  CoreData                            0x00000001024180b0 -[NSManagedObject didChangeValueForKey:withSetMutation:usingObjects:] + 80
    13  CoreData                            0x000000010242fa11 -[_NSNotifyingWrapperMutableSet addObject:] + 161

编辑:一些澄清。 Teams 和 Event 具有多对多的无序关系。

【问题讨论】:

标签: ios core-data swift nsset


【解决方案1】:

是的!我找到了答案!

我在 Events.swift 类(关系的另一端)中创建了一个新函数。

我写了以下代码:

import Foundation
import CoreData

class Event: NSManagedObject {

    @NSManaged var timeStamp: NSDate
    @NSManaged var teams: NSSet

}

extension Event {

    func addTeamToEvent(team:Teams) {
        var teamz = self.mutableSetValueForKey("teams")
        teamz.addObject(team)
    }

    func getNumberOfTeams() -> Int {
        return self.teams.count;
    }

    func getTeams() -> [Teams] {
        var tmpsak: [Teams]
        tmpsak = self.teams.allObjects as [Teams]
        tmpsak = self.teams.allObjects as [Teams]

        return tmpsak
    }

}

我认为是无关的。但是,将 getTeams 重命名为 getTeamsAsArray 消除了该问题。我猜 CoreData 在填写关系的另一端时使用了一个名为 getTeams() 的内置函数(因为另一个类称为 Teams)。我不小心覆盖(?)它,导致它失败。

感谢您的建议,希望对其他人有所帮助!

在一些相关的说明中,几年前发现了一个具有类似症状的错误(并且似乎仍然存在),当使用 ordered 多对时,它会在自动生成的代码中显示出来- 许多关系。

【讨论】:

  • 如果您查看 Apple 提供的代码提示,您应该将自定义方法添加到子类而不是扩展。阅读他们在 cmets 中所说的话。他们在扩展中写道:“// 从核心数据编辑器菜单中选择“创建 NSManagedObject 子类...” // 为您更新的模型删除并重新创建此实现文件。”他们在子类中写道:“// 在此处插入代码以向托管对象子类添加功能”。苹果通常不会无缘无故地用 cmets 说话。如果您重新生成这些子类,您的代码将被覆盖。
  • 另外,只需将您的集合转换为 NSMutableSet。由于编译器无法检查此字符串,因此使用密钥执行此操作很容易出错。
  • 这实际上也对我有用!我有一个函数getChoices,其中选择是一个ToMany 关系,因此是一个@NSManaged var choices: NSSet? 变量。当我将它从 getChoices 更改为 getChoicesAsArray 时,问题就消失了。
  • 啊谢谢!!!这让我倒退了很长一段路。这让我发疯了。
  • 我也遇到了同样的问题。我有一个名为getFields() 的方法,还有一个名为fields 的关系,它们显然发生了冲突。这真的很糟糕,因为我需要使用 getFields 来支持我的应用程序中的 JavaScriptCore API。但我需要它返回一个数组而不是 Set
【解决方案2】:

如果您使用 Objective C 生成的 NSManagedObject 子类,它们包含用于添加单个对象的自定义方法 - 我认为这些方法已经过尝试和测试,并且看起来比目前的 swift 更好。

理论上,您只需要使用您创建的任何新集合来设置新集合。一种选择是:

    var matchobjs = matches.allObjects as [Event]
    matchobjs.append(event)
    matches = NSSet(array: matchobjs)

但是错误看起来与this post:非常相似

在我看来,多对多关系又发生了一些可疑的事情......

【讨论】:

  • 感谢您的回复!然而,新代码也不起作用,我在语句“matches = NSSet(array:matchobjs)”中收到与以前相同的错误消息
  • 我建议使用目标 C 生成的标头然后,它们为您提供方法 - 只需将标头名称添加到桥接头。这个错误很奇怪,可能是一个错误,我试图用快速生成的标头创建一个项目,但我发现即使是最简单的东西也会中断 - 好的,所以这有时会发生在测试版中。顺便说一下,这个错误看起来像是一个长期存在的错误,具有多对多关系,也许快速生成的标头做了一些奇怪的事情导致同样的事情发生......
猜你喜欢
  • 2015-09-08
  • 1970-01-01
  • 1970-01-01
  • 2011-11-06
  • 1970-01-01
  • 2020-09-04
  • 2014-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多