CoreData - 无法将空字符串设置为属性的默认值

gle*_*enc 38 migration string xcode core-data

我的datamodel中有一个实体,其字符串属性当前是可选的,我想将其转换为必需属性,其默认值为空字符串.

正如其他人发现的那样,在Xcode CoreData数据建模器中将默认值保留为空会导致验证错误(因为设计者将此解释为NULL),但尝试使用'',""或@""作为默认值会导致这些文字根据需要,字符被解释为默认字符,而不是空的零长度字符串.

我确实在谷歌上发现了这个帖子,但是,除了解决方案真的很丑陋(模型定义在.xcdatamodel和objc源之间拆分)之外,它也不适用于轻量级迁移,因为这些迁移完全基于.xcdatamodel文件和实体实现中的objc逻辑未加载.

有没有办法在数据模型设计师中实现这一目标?

Tec*_*Zen 31

这是一个非常有趣的问题.经过一些测试后,我认为这是不可能的,因为数据模型中的文本字段的配置方式.

原则上,您可以使用unicode空集字符\u2205来表示默认的空字符串,但文本字段似乎不接受任何转义,因此它将任何尝试转义unicode字符代码转换为代码字符本身的文字字符串例如,输入'\ u2205'最终为文字'\ u2205'.

理论上,您可以编写一个实用程序app来读取图形生成的托管对象模型文件,然后以编程方式将属性default设置为等于空字符串,然后将文件保存回磁盘.我说"理论上"是因为没有记录的方法来保存代码中的托管对象模型文件.您可以读取一个并在内存中修改它,但不能保留更改.

我认为有点疏忽.

我认为您没有其他选择,只能在模型首次加载时以实际方式设置默认空字符串.这很简单,但它很丑,你必须记住你做过(特别是如果你迁移版本),但我认为现在这是唯一的选择.


Sco*_*rks 16

鞭打你最喜欢的XML编辑器(我刚刚使用了Emacs)并深入到捆绑包内的捆绑包内的contents文件.然后只需在括号内的元素中添加XML属性即可.这是一个例子:.xcdatamodel.xcdatamodelddefaultValueString=""<attribute>...</attribute><entity>...</entity>

<attribute name="email" attributeType="String" defaultValueString="" syncable="YES"/>
Run Code Online (Sandbox Code Playgroud)

我不能说这是否能够幸存下来,因为我还没有这么做.

  • 这是一个毫无价值的评论:"这是一个可怕的想法." 也许建议更好的东西会更有帮助吗?我的概念虽然肯定使用了`contents`文件可能改变的结构的知识,但至少模拟了CoreData数据建模器而没有这个错误的特性.所有其他解决方案都是相对重量级的代码改进,应该在设计时解决一个问题,即使用非错误的建模器. (3认同)

Sas*_*sha 7

我通过覆盖我的字段的getter来解决这个问题 - 如果它包含null,我会返回一个空字符串:

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

到目前为止它似乎正在做这个伎俩,我想它不会影响迁移(虽然我不太了解它们肯定会说).毕竟,我真的不在乎数据库中是否有空字符串或空字符串 - 只要我在询问字段时得到""而不是null.


Dav*_*tti 6

我解决这个问题的方法是创建一个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]];
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 一个建议基于`awakeFromInsert`的文档 - 而不是使用`setValue:forKey:`use`setPrimitiveValue:forKey:`以便不触发KVO. (2认同)