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
и т.д.