Swift + CoreData: невозможно установить Bool в подкласс NSManagedObject - ошибка?

У меня есть немного странная проблема, которую я не могу понять, у меня есть простой объект с пользовательским подклассом NSManagedObject:

@objc(EntityTest) class EntityTest: NSManagedObject {

    @NSManaged var crDate: NSDate
    @NSManaged var name: String
    @NSManaged var completed: Bool
    @NSManaged var completedOn: NSDate
}

Это проблема, я могу создать объект в порядке и установить все значения и сохранить в массиве. Как бы то ни было, когда я пытаюсь получить один и тот же объект, я могу установить все значения EXCEPT в поле "complete". Я получаю ошибку времени выполнения, говоря "EXC_BAD_ACCESS", я могу прочитать значение, просто не могу его установить.

Отладчик указывает на:

0x32d40ae:  je     0x32d4110                 ; objc_msgSend + 108
0x32d40b0:  movl   (%eax), %edx

Возможно, некоторые проблемы из-за того, что он рассматривается как класс Objective-C и пытается отправить сообщение для установки boolean, которое, как мне известно, немного смешно с CoreData, первоначально представляющим их как NSNumbers.

Любые идеи? Я сам создал класс, он не генерируется.

EDIT:

entity.crDate = NSDate() // succeeds
entity.completed = false // fails
entity.completed.setValue(false, forKey: "completed") //succeeds

Итак, для установки bool использование setValue из NSManagedObject работает, но не для прямых сеттеров, хотя для свойств non-bool я могу установить его с помощью установщиков.

UPDATE:

Проверяя это немного больше, кажется, что в первый раз, когда я установил значение после получения из NSEntityDescription, он использует обычные методы доступа Swift. Позже, когда я пытаюсь получить доступ к одному и тому же объекту (который хранился в массиве), он пытается рассматривать его как объект стиля Objective-C и отправляет сообщение для метода с именем "setCompleted" . Я предполагаю, что это имеет смысл, поскольку я использую точечную нотацию для доступа к ней, и я использовал директиву @objc.

Я проверил это, создав метод "setCompleted" , однако в методе я установил значение с помощью "completed = newValue", что делает рекурсивный вызов "setCompleted" , из-за которого он сбой... Странно, поэтому при этом момент все еще не может иметь правильного исправления. Кажется, это происходит только с Bools.

Только обходной путь использует метод setValueForKey для NSManagedObject. Возможно, это файл отчета об ошибке?

Ответы

Ответ 1

Если вы позволяете Xcode 6 Beta 3 создавать файлы Swift для своих объектов, он создаст свойства NSNumber для типа CoreData Boolean.

enter image description here

Однако вы можете использовать Bool как тип Swift вместо NSNumber, который работал у меня, не используя синтаксис точек. Он установит Swift Bool с NSNumber, что может привести к ошибке в синтаксисе точки.


Чтобы сделать это явным, вы должны использовать тип NSNumber для атрибутов в сущности с типом Boolean. Затем создайте вычисленное свойство (в iBook The Swift язык программирования в разделе Language Guide → Properties → Computed Properties), чтобы вернуть Swift Bool. Поэтому никогда не будет храниться Bool.

Так же:

@NSManaged var snack: NSNumber
var isSnack: Bool {
    get {
        return Bool(snack)
    }
    set {
        snack = NSNumber(bool: newValue)
    }
}

Конечно, было бы здорово скрыть другой (атрибут NSNumber), но будьте терпеливы, и Apple в будущем будет реализовывать частные атрибуты.


Изменить:

Если вы установите флажок создать типы skalar, он даже будет использовать тип Bool в автоматически создаваемом файле Swift!

Итак, я думаю, что это ошибка.

Ответ 2

Следуя от Сэя Букингема, который полностью прав. Вы пытаетесь сохранить примитивный тип в основных данных, где он ожидает NSNumber.

Правильное использование будет entity.completed = NSNumber.numberWithBool(false)

Вот почему вы не можете получить это завершенное значение как bool напрямую, и поэтому вам нужно будет написать:

var: Bool? = entity.completed.boolValue()

Ответ 3

Вы можете сбрасывать свою собственность из NSNumber до типа Bool следующим образом:

var someBoolVariable = numberValue as Bool    

Он работает для меня таким образом:

self.twoFactorAuthEnabledSwitch.enabled = userProfile?.twoFactorEnabled as Bool

Ответ 4

В XCode 8 Просто установите:

user.isLoggedIn = true

его работы как шарм

Ответ 5

Я не коснулся быстро, но в Objective-C BOOL не является объектом и не может быть объектом. Это примитив, и похоже, вы пытаетесь рассказать класс Objective-C для обработки BOOL как объекта. Но я мог бы это сделать, поскольку я не знаком с тем, что @NSManaged делает под капотом.

https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/FoundationTypesandCollections/FoundationTypesandCollections.html

Ответ 6

Я обнаружил, что он отлично работает, если вы укажете имя и модуль класса в модели данных (вместо того, чтобы оставить по умолчанию NSManagedObject).

Как только я это установлю, я могу без проблем использовать Bool, Int16, Int32 и т.д.