CoreData – 不能将空string设置为属性的默认值

我在我的datamodel有一个string属性,目前是可选的实体,我想将其转换为一个默认值为空string的必需属性。

正如其他人发现的那样,在Xcode CoreData数据build模器中保留默认值为空白会导致validation错误(因为devise者将其解释为NULL),但是将默认值“',”“或@”“作为默认值导致这些文字字符被解释为默认值,而不是根据需要的空的零长度string。

但是,我确实在Google上find了这个线程 ,除了这个解决scheme真的很难看(模型定义在.xcdatamodel和objc源文件之间划分)之外,它也不适用于轻量级迁移,因为这些迁移完全基于.xcdatamodel文件和实体实现中的objc逻辑没有加载。

在数据模型devise器中有没有办法实现这一点?

这是一个非常有趣的问题。 经过一些testing,我不认为这是可能的,因为数据模型中的文本字段的configuration方式。

原则上,您可以使用\u2205的unicode空集字符来表示默认的空string,但是文本字段似乎不接受任何转义符,因此它将任何尝试将unicode字符代码转义为代码的文字string字符本身(例如,input'\ u2205')最终成为字面文本'\ u2205'。

从理论上讲,您可以编写一个实用程序来读取graphics生成的托pipe对象模型文件,然后以编程方式将属性default设置为等于一个空string,然后将该文件保存回磁盘。 我说“理论上”,因为没有文件记载的方式来保存从代码pipe理的对象模型文件。 您可以阅读并在内存中修改它,但不能保留更改。

我认为这是一个疏忽。

我不认为你有什么select,只能在模型第一次加载的时候实际地设置默认的空string。 这很简单,但它很丑,你将不得不记得你做了(特别是如果你迁移版本),但我认为现在是唯一的select。

鞭出你最喜欢的XML编辑器(我只是使用Emacs),并下潜到.xcdatamodel包内的.xcdatamodeld包内的contents文件。 然后,只需在<entity>...</entity>内的<attribute>...</attribute>元素中添加一个defaultValueString="" XML属性。 这是一个例子:

 <attribute name="email" attributeType="String" defaultValueString="" syncable="YES"/> 

我不能说这是否能够幸免于难,因为我还没有这样做。

我解决了这个通过覆盖我的领域的getter – 如果它包含null,我返回一个空string,而不是:

 -(NSString *)unit { if ([self primitiveValueForKey:@"unit"] == NULL) { return @""; } else { return [self primitiveValueForKey:@"unit"]; } } 

到目前为止,这似乎是在伎俩,我想这不会影响迁移(虽然我不知道他们肯定说)。 毕竟,我并不关心数据库中是否有空string,只要我在请求字段的时候得到“”而不是null。

我解决这个问题的方法是创build一个NSManagedObject子类,并在awakeFromInsert处理空string的空值replace。 然后我把所有的实体设置为这个子类的子NSManagedObject而不是NSManagedObjectNSManagedObject 。 这里的假设是,我希望默认情况下给定实体中的每个string属性都设置为空string(如果您希望在同一个实体中保留NULL,那么这将不起作用,或者至less需要额外的逻辑) 。

这样做可能是一种更高效的方式,但是由于它只是在实体创build时被调用,所以我认为这不是太多的性能问题。

 - (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]]; } } } } 

你可以手动完成。 在您的模型类中,重写awakeFromInsert并将您的string设置为空string

迅速:

 override func awakeFromInsert() { super.awakeFromInsert() self.stringProperty = "" } 

Objective-C的

 - (void) awakeFromInsert { [super awakeFromInsert]; self.stringProperty = @""; } 

这是基于David Ravetti的回答和edelaney05的评论的Swift解决scheme。 另外,我添加了选项检查。

此解决scheme在我的项目中工作正常。

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