通过对象的枚举属性使用 NSPredicate 获取核心数据托管对象的问题
Posted
技术标签:
【中文标题】通过对象的枚举属性使用 NSPredicate 获取核心数据托管对象的问题【英文标题】:Issue with fetching Core Data managed object using NSPredicate by object's enum attribute 【发布时间】:2020-02-09 23:40:36 【问题描述】:我在获取具有enum
属性和Int16
rawValues 的Core Data 托管对象时遇到问题。调用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
崩溃消息是:
线程 1:EXC_BAD_ACCESS(代码=1,地址=0x3)
当我用以下内容更改第 3 行时,我得到了另一种错误。
这是替代代码:
fetchRequest.predicate = NSPredicate(format: "%K = %@", #keyPath(Book.bookType), bookType as! CVarArg)
这是替代代码导致的错误:
线程 1:信号 SIGABRT
我在调试输出中看到了这一点:
无法转换类型“ProjectName.BookType”的值 (0x10ac10098) 到 '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
属性从我的 Core Data 存储中正确获取 Book
对象,该属性位于 @objc enum
类型和 Int16
rawValues 中?
更新:
我已经按照 Jesse Squires 的建议 in a presentation 尝试了其他方法:
-
从
enum
的定义中删除了@objc
关键字
使用private
和public
属性访问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 立即抱怨:
参数类型“BookType”不符合预期的类型“CVarArg”
如果我改用bookType.rawValue
,XCode 就会停止抱怨。但是,程序在运行时崩溃并出现上述相同的错误(第一个)。
更新 2:
我已将社区建议的答案应用到this question。更具体地说,我已经尝试了使用%i
或@ld
而不是%@
的问题答案中的建议,如下所示:
fetchRequest.predicate = NSPredicate(format: "bookTypeValue == %i", bookType.rawValue)
我尝试了另一个使用字符串插值的建议,如下所示:
fetchRequest.predicate = NSPredicate(format: "bookTypeValue == %@", "\(bookType.rawValue)")
这些代码更改防止了崩溃,但 func returnBook
返回 nil,即使我确定数据在那里。由于某种原因,获取或比较失败...
【问题讨论】:
我猜bookType必须在模型编辑器中定义为Transformable?当你把它重命名为 bookTypeValue 时,你是不是把它改成了 Integer?谓词不适用于可转换属性(至少在获取时不行)。 @pbasdf bookType 在模型编辑器中被定义为 Int16(这里建议:***.com/a/31681870/3780985),在我将它重命名为 bookTypeValue 后,它在模型编辑器中仍然与 Int16 相同。我只是将代码中的类型从 BookType 更改为 Int16。 【参考方案1】:在为这个问题苦苦挣扎了几个小时后,我终于设法解决了。
这是我按时间顺序为解决问题所做的工作:
-
我已将
bookTypeValue
的类型从Int16
更改为Int32
,因为我在官方(存档)documentation 中看不到16 位整数的格式说明符。我已经测试过,我可以确认,如果您在此处使用 %@
而不是正确的格式说明符,即 %d
用于有符号的 32 位整数,则会出现问题中的第一个错误:
线程 1:EXC_BAD_ACCESS(代码=1,地址=0x3)
我已经像这样更改了NSPredicate(format:)
调用:
fetchRequest.predicate = NSPredicate(格式: "bookTypeValue == %d", bookType.rawValue)
我已经更改了returnBook
func 中的第 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)")
【讨论】:
以上是关于通过对象的枚举属性使用 NSPredicate 获取核心数据托管对象的问题的主要内容,如果未能解决你的问题,请参考以下文章
如何将 @FetchRequest 属性包装器的新 nsPredicate 动态属性与传递给 View 的对象一起使用