I have an issue with fetching a Core Data managed object which has an enum
attribute with Int16
rawValues. The program crashes when calling NSPredicate(format:)
.
This is the code (3rd line) that results a crash:
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)
When I change the 3rd line with the following, I get another kind of error.
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
And I see this in the debug output:
Could not cast value of type 'ProjectName.BookType' (0x10ac10098) to '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?
Update:
I have tried something else as suggested in a presentation by Jesse Squires:
@objc
keyword from enum
's definitionprivate
and public
properties to access the enum
's instances... 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
.
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:
Argument type 'BookType' does not conform to expected type 'CVarArg'
XCode stops complaining if I use bookType.rawValue
instead. However, program crashes during runtime with the same error above (first one).
Update 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:
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. 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:
bookTypeValue
from Int16
to Int32
, because I could not see a format specifier for 16-bit integers in the official (archived) documentation . 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:Thread 1: EXC_BAD_ACCESS (code=1, address=0x3)
I have changed the NSPredicate(format:)
call like so:
fetchRequest.predicate = NSPredicate(format: "bookTypeValue == %d", bookType.rawValue)
I have changed the 5th line in returnBook
func like so:
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)") }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.