Проблема с извлечением управляемого объекта Core Data с использованием NSPredicate по атрибуту enum объекта - PullRequest
2 голосов
/ 10 февраля 2020

У меня проблема с извлечением управляемого объекта Core Data, который имеет атрибут enum с Int16 rawValues. Сбой программы при вызове NSPredicate(format:).

. Этот код (3-я строка) приводит к появлению сообщения cra sh:

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
}

Cra sh:

Поток 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
}

Мой вопрос: Как правильно извлечь объект Book из моего хранилища основных данных, используя его bookType атрибут, который имеет тип @objc enum с Int16 rawValues?

Обновление:

Я пробовал что-то еще в качестве подсказки d в презентации Джесси Сквайрс:

  1. Удалено ключевое слово @objc из определения enum
  2. Используется private и public свойства для доступа к экземплярам enum ...

Я изменил свой код, как предложено в связанной презентации, и я изменил имя атрибута bookType в Базовых данных ".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
}

И я попытался извлечь, используя личное значение, как предложено в презентации, связанной выше ...:

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

Однако я не мог решить моя проблема с этим методом также ... XCode немедленно жалуется:

Тип аргумента 'BookType' не соответствует ожидаемому типу 'CVarArg'

XCode прекращает жаловаться, если я используйте вместо этого bookType.rawValue. Однако во время выполнения программа вылетает с той же ошибкой, что и выше (первая).

Обновление 2:

Я применил ответы, данные этот вопрос , который предлагается сообществом. Чтобы быть более точным c, я попробовал предложение в ответе на этот вопрос, который использует %i или @ld вместо %@, например, так:

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

, и у меня есть попробовал другое предложение, использующее интерполяцию строк следующим образом:

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

Эти изменения кода предотвратили сбои, но fun c returnBook возвращает ноль, даже если я уверен, что данные есть. Выборка или сравнение по какой-то причине не удается ...

1 Ответ

0 голосов
/ 11 февраля 2020

После долгих часов борьбы с этой проблемой мне наконец удалось ее решить.

Вот что я сделал, чтобы решить проблему в хронологическом порядке:

  1. Я изменил тип bookTypeValue с Int16 на Int32, потому что я мог не вижу спецификатора формата для 16-битных целых чисел в официальной (заархивированной) документации . Я проверил и могу подтвердить, что если вы используете %@ здесь вместо правильного спецификатора формата, который равен %d для 32-разрядных целых чисел со знаком, вы получите первую ошибку в вопросе:

Тема 1: EXC_BAD_ACCESS (код = 1, адрес = 0x3)

Я изменил вызов NSPredicate(format:) следующим образом:

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

Я изменил 5-ю строку в returnBook fun c примерно так:

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