通过对象的枚举属性使用 NSPredicate 获取核心数据管理对象的问题

Issue with fetching Core Data managed object using NSPredicate by object's enum attribute

我在获取具有 enum 属性和 Int16 rawValues 的核心数据托管对象时遇到问题。程序在调用 NSPredicate(format:).

时崩溃

这是导致崩溃的代码(第 3 行):

func returnBook (bookType: BookType) -> Book? {
    let fetchRequest = NSFetchRequest<Book>(entityName: "Book")
    fetchRequest.predicate = NSPredicate(format: "%K = %@", #keyPath(Book.bookType), bookType.rawValue as CVarArg)
    fetchRequest.fetchLimit = 1
    let book = (try? fetchRequest.execute())?.first
    return book
}

崩溃信息是:

Thread 1: EXC_BAD_ACCESS (code=1, address=0x3)

当我将第 3 行更改为以下内容时,出现另一种错误。

这是备用代码:

fetchRequest.predicate = NSPredicate(format: "%K = %@", #keyPath(Book.bookType), bookType as! CVarArg)

这是替代代码导致的错误:

Thread 1: signal SIGABRT

我在调试输出中看到了这个:

Could not cast value of type 'ProjectName.BookType' (0x10ac10098) to 'Swift.CVarArg' (0x10b698548).

下面是项目中的其他一些相关代码:

@objc(Book)
public class Book: NSManagedObject {
    // …
}

extension Book {

    @NSManaged public var bookType: BookType

}

@objc public enum BookType: Int16 {
    case fiction    = 0
    case nonFiction = 1
    case reference  = 2
}

我的问题:如何使用 bookType 属性从我的核心数据存储中正确获取 Book 对象,该属性位于 @objc enum 键入 Int16 rawValues?

更新:

我已经按照 Jesse Squires in a presentation 的建议尝试了其他方法:

  1. enum 的定义
  2. 中删除了 @objc 关键字
  3. 使用 privatepublic 属性访问 enum 的实例...

我已经按照链接演示文稿中的建议更改了我的代码,并且我已经将 Core Data 的“.xcdatamodeld”文件中的 bookType 属性的名称更改为 bookTypeValue.

extension Book {

    public var bookType: BookType {
        get {
            return BookType(rawValue: self.bookTypeValue)!
        }
        set {
            self.bookTypeValue = newValue.rawValue
        }
    }

    @NSManaged private var bookTypeValue: Int16

}

public enum BookType: Int16 {
    case fiction    = 0
    case nonFiction = 1
    case reference  = 2
}

并且我尝试使用上面链接的演示文稿中建议的私有值来获取...:

fetchRequest.predicate = NSPredicate(format: "bookTypeValue == %@", bookType)

但是我用这个方法也解决不了我的问题...XCode马上投诉:

Argument type 'BookType' does not conform to expected type 'CVarArg'

如果我改用 bookType.rawValue

XCode 就会停止抱怨。但是,程序在运行时崩溃并出现与上述相同的错误(第一个)。

更新二:

我已经应用了社区建议的 的答案。更具体地说,我已经尝试了使用 %i@ld 而不是 %@ 的问题答案中的建议,如下所示:

fetchRequest.predicate = NSPredicate(format: "bookTypeValue == %i", bookType.rawValue)

我已经尝试了另一个建议,它使用字符串插值,如下所示:

fetchRequest.predicate = NSPredicate(format: "bookTypeValue == %@", "\(bookType.rawValue)")

这些代码更改防止了崩溃,但是 func returnBook returns nil,即使我确定数据在那里。由于某种原因获取或比较失败...

在为这个问题苦苦挣扎了好几个小时之后,我终于设法解决了它。

以下是我为解决问题所做的工作(按时间顺序排列):

  1. 我已经将 bookTypeValue 的类型从 Int16 更改为 Int32,因为我在官方(存档)中看不到 16 位整数的格式说明符 documentation。我已经测试过,我可以确认,如果您在此处使用 %@ 而不是正确的格式说明符(对于带符号的 32 位整数是 %d ),您会得到问题中的第一个错误:

Thread 1: EXC_BAD_ACCESS (code=1, address=0x3)

  1. 我已将 NSPredicate(format:) 调用更改为:

    fetchRequest.predicate = NSPredicate(格式: "bookTypeValue == %d", bookType.rawValue)

  2. 我在 returnBook 函数中更改了第 5 行,如下所示:

     do {
        let results = try coreDataStack.managedContext.fetch(fetchRequest)
        if results.count > 0 {
            book = results.first
            return book
        } 
     } catch let error as NSError {
        print("Fetch error: \(error) description: \(error.userInfo)")
     }