简体   繁体   English

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

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

I have an issue with fetching a Core Data managed object which has an enum attribute with Int16 rawValues.我在获取具有Int16 rawValues 的enum属性的 Core Data 托管对象时遇到问题。 The program crashes when calling NSPredicate(format:) .调用NSPredicate(format:)时程序崩溃。

This is the code (3rd line) that results a crash:这是导致崩溃的代码(第 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
}

Crash message is:崩溃消息是:

Thread 1: EXC_BAD_ACCESS (code=1, address=0x3)线程 1:EXC_BAD_ACCESS(代码=1,地址=0x3)

When I change the 3rd line with the following, I get another kind of error.当我使用以下内容更改第 3 行时,出现另一种错误。

This is the alternative code:这是替代代码:

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

And this is the error resulted by that alternative code:这是该替代代码导致的错误:

Thread 1: signal SIGABRT线程 1:信号 SIGABRT

And I see this in the debug output:我在调试输出中看到了这一点:

Could not cast value of type 'ProjectName.BookType' (0x10ac10098) to 'Swift.CVarArg' (0x10b698548).无法将“ProjectName.BookType”(0x10ac10098)类型的值转换为“Swift.CVarArg”(0x10b698548)。

Here are some other related code in the Project:以下是项目中的其他一些相关代码:

@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
}

My question: How can I properly fetch the Book object from my Core Data store by using its bookType attribute, which is in an @objc enum type with Int16 rawValues?我的问题:如何使用bookType属性从我的 Core Data 存储中正确获取Book对象,该属性位于具有Int16 rawValues 的@objc enum类型中?

Update:更新:

I have tried something else as suggested in a presentation by Jesse Squires:我已经按照 Jesse Squires 的演示文稿中的建议尝试了其他方法:

  1. Removed @objc keyword from enum 's definitionenum的定义中删除了@objc关键字
  2. Used private and public properties to access the enum 's instances...使用privatepublic属性来访问enum的实例...

I have changed my code as suggested in the linked presentation, and I have changed the name of bookType attribute in Core Data's ".xcdatamodeld" file to bookTypeValue .我已按照链接演示文稿中的建议更改了代码,并将 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
}

And I tried to fetch using the private value as suggested in the presentation linked above...:我尝试使用上面链接的演示文稿中建议的私有值来获取...:

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

However I could not solve my problem with this method either... XCode complains immediately:但是我也无法用这种方法解决我的问题...... XCode 立即抱怨:

Argument type 'BookType' does not conform to expected type 'CVarArg'参数类型“BookType”不符合预期类型“CVarArg”

XCode stops complaining if I use bookType.rawValue instead.如果我改用bookType.rawValue XCode 就会停止抱怨。 However, program crashes during runtime with the same error above (first one).但是,程序在运行时崩溃并出现上述相同的错误(第一个)。

Update 2:更新 2:

I have applied the answers given to this question which is suggested by the community.我已经应用了社区建议的这个问题的答案。 To be more specific, I have tried the suggestion in the answer to that question which is using %i , or @ld instead of %@ like so:更具体地说,我在使用%i@ld而不是%@问题的答案中尝试了建议,如下所示:

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

and I have tried the other suggestion which is using String interpolation like so:我已经尝试了另一个使用字符串插值的建议,如下所示:

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

These code changes prevented crashes, but func returnBook returns nil, even if I am sure that the data is there.这些代码更改防止了崩溃,但 func returnBook返回 nil,即使我确定数据在那里。 Fetch or comparison fails for some reason...由于某种原因,获取或比较失败...

After struggling with this problem for many hours finally I have managed to solve it.在为这个问题苦苦挣扎了几个小时后,我终于设法解决了它。

Here is what I have done to solve the problem in chronological order:以下是我为按时间顺序解决问题所做的工作:

  1. I have changed the type of bookTypeValue from Int16 to Int32 , because I could not see a format specifier for 16-bit integers in the official (archived) documentation .我已将bookTypeValue的类型从Int16更改为Int32 ,因为我在官方(存档) 文档中看不到 16 位整数的格式说明符。 I have tested and I can confirm that if you use %@ here instead of correct format specifier, which is %d for signed 32-bit integers, you get the first error in the question:我已经测试过,我可以确认,如果您在此处使用%@而不是正确的格式说明符(对于有符号 32 位整数是%d ,您会得到问题中的第一个错误:

Thread 1: EXC_BAD_ACCESS (code=1, address=0x3)线程 1:EXC_BAD_ACCESS(代码=1,地址=0x3)

  1. I have changed the NSPredicate(format:) call like so:我已经更改了NSPredicate(format:)调用,如下所示:

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

  2. I have changed the 5th line in returnBook func like so:我已经更改了returnBook func 中的第 5 行, returnBook所示:

     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)") }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM