CoreData - не может установить пустую строку как значение по умолчанию для атрибута
У меня есть объект в моем datamodel со строковым атрибутом, который в настоящее время является необязательным, и я хотел бы преобразовать его в требуемый атрибут со значением по умолчанию пустой строки.
Как выяснили другие, оставив значение по умолчанию пустым в модуле данных Xcode CoreData, возникают ошибки проверки (поскольку разработчик интерпретирует это как NULL), но при попытке '', "или @" в качестве значения по умолчанию в этих буквальных символах интерпретируется как значение по умолчанию, а не пустая строка нулевой длины, по желанию.
Я нашел этот поток в Google, однако, помимо того, что решение было действительно уродливым (определение модели разделено между .xcdatamodel и objc-источником), оно также не работает работа для облегченных миграций, потому что эти миграции выполняются исключительно на основе файлов .xcdatamodel, а логика objc из ваших реализаций объекта не загружается.
Есть ли способ достичь этого в дизайнере модели данных?
Ответы
Ответ 1
Это очень интересный вопрос. После некоторого тестирования я не думаю, что это возможно из-за того, как настроено текстовое поле в модели данных.
В принципе, вы можете использовать символ unicode с пустым множеством \u2205
для представления пустой строки по умолчанию, но текстовое поле, похоже, не принимает никаких экранов, поэтому оно преобразует любую попытку избежать символьного кода юникода в литерал строка символов кода, например ввод '\ u2205' заканчивается как буквальный текст '\ u2205'.
В теории вы можете написать приложение-утилиту для чтения в графически создаваемом файле модели управляемых объектов, а затем программным образом установить атрибут по умолчанию равным пустой строке, а затем сохранить файл обратно на диск. Я говорю "теоретически", потому что нет документального способа сохранения файла модели управляемого объекта из кода. Вы можете прочитать его и изменить его в памяти, но не сохранять изменения.
Немного надзора, я думаю.
Я не думаю, что у вас есть выбор, кроме как прагматически задавать пустую строку по умолчанию при первой загрузке модели. Это просто сделать, но это уродливо, и вам придется помнить, что вы это сделали (особенно если вы переносите версии), но я думаю, что сейчас это единственный выбор.
Ответ 2
Выньте свой любимый редактор XML (я только что использовал Emacs) и погрузитесь в файл contents
внутри пакета .xcdatamodel
внутри пакета .xcdatamodeld
. Затем просто добавьте атрибут defaultValueString=""
XML в элемент <attribute>...</attribute>
внутри скобок <entity>...</entity>
.
Вот пример:
<attribute name="email" attributeType="String" defaultValueString="" syncable="YES"/>
Я не могу говорить о том, выживает ли это миграция, так как мне еще не приходилось это делать.
Ответ 3
Я решил это, переопределив getter для моего поля - если он содержит null, вместо этого я возвращаю пустую строку:
-(NSString *)unit {
if ([self primitiveValueForKey:@"unit"] == NULL) {
return @"";
} else {
return [self primitiveValueForKey:@"unit"];
}
}
Пока это похоже на трюк, и я бы предположил, что это не повлияет на миграцию (хотя я не знаю достаточно о них, чтобы точно сказать). Мне все равно, есть ли нуль или пустая строка в db, в конце концов - до тех пор, пока я получаю "вместо", когда запрашиваю поле.
Ответ 4
Мой подход к решению этой проблемы заключался в создании подкласса NSManagedObject
и обработки подстановки пустых строк для значений NULL в awakeFromInsert
. Затем я устанавливаю все сущности как дочерние элементы этого подкласса, а не дочерние элементы NSManagedObject
. Предположение здесь состоит в том, что я хочу, чтобы по умолчанию атрибут каждый в пределах заданного объекта был установлен на пустую строку по умолчанию (он не работает или, по крайней мере, потребует дополнительной логики, если вы хотите, чтобы некоторые остаются NULL в пределах одного и того же объекта).
Вероятно, это более эффективный способ сделать это, но поскольку он только призван к созданию сущности, я не думаю, что это слишком большой успех.
- (void)awakeFromInsert {
[super awakeFromInsert];
NSDictionary *allAttributes = [[self entity] attributesByName];
NSAttributeDescription *oneAttribute;
for (NSString *oneAttributeKey in allAttributes) {
oneAttribute = [allAttributes objectForKey:oneAttributeKey];
if ([oneAttribute attributeType] == NSStringAttributeType) {
if (![self valueForKey:[oneAttribute name]]) {
[self setValue:@"" forKey:[oneAttribute name]];
}
}
}
}
Ответ 5
Вы можете сделать это вручную.
В вашем классе модели переопределите awakeFromInsert и установите строки в пустую строку
Swift:
override func awakeFromInsert()
{
super.awakeFromInsert()
self.stringProperty = ""
}
Objective-C
- (void) awakeFromInsert
{
[super awakeFromInsert];
self.stringProperty = @"";
}
Ответ 6
Вот решение Swift, основанное на ответе Дэвида Раветти и комментарий edelaney05. Кроме того, я добавил проверку доступности.
Это решение отлично работает в моих проектах.
class ExampleEntity: NSManagedObject {
...
override func awakeFromInsert() {
super.awakeFromInsert()
for (key, attr) in self.entity.attributesByName {
if attr.attributeType == .stringAttributeType && !attr.isOptional {
if self.value(forKey: key) == nil {
self.setPrimitiveValue("", forKey: key)
}
}
}
}
...
}
Ответ 7
Более простое решение, основанное на ответе Скотта Маркса, позволяет избежать синтаксических ошибок:
Во-первых, временно установите значение по умолчанию, чтобы его было легко найти, что-то вроде того, что here you are
. Откройте в любом текстовом редакторе файл contents
внутри пакета .xcdatamodel
внутри пакета .xcdatamodeld
. Затем просто выполните поиск с заменой строки "here you are"
на ""
в этом файле.
Миграция прошла без проблем.
Ответ 8
Может быть, я опоздал с этим ответом, но я был в Google и нашел этот форум.
Решение очень простое:
- При нажатии на xcdatamodelId (на левом экране)
- Изменить вид сущности на график
- Дважды щелкните любой атрибут, который вы хотите, и меню появится справа.
Все изменения просты.
Часть 2
![For Part 2]()
Часть 3
![For Part 3]()