在 CoreData 实体中将属性从 NSNumber 转换为 NSString - LightWeightMigration

Posted

技术标签:

【中文标题】在 CoreData 实体中将属性从 NSNumber 转换为 NSString - LightWeightMigration【英文标题】:Convert attribute from NSNumber to NSString in CoreData Entity - LightWeightMigration 【发布时间】:2017-10-23 15:12:33 【问题描述】:

我正在尝试使用目标 C 中的轻量级迁移将 NSNumber 迁移到 NSString 属性。版本 0

第 2 版

我已将核心数据模型当前版本更改为 2

由于它不会在轻量级迁移中得到解决,我尝试使用 CoreDataMapping 模型和 NSEntity 迁移策略,如下所示。

创建了 NSEntityMigrationPolicy 的子类并尝试了以下代码

@interface SampleMigrationV1toV2 : NSEntityMigrationPolicy

@end

#import "SampleMigrationV1toV2.h"

@implementation SampleMigrationV1toV2

- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error

    NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:[mapping destinationEntityName] inManagedObjectContext:[manager destinationContext]];

    // Copy all the values from sInstance into newObject, making sure to apply the conversion for the string to int when appropriate. So you should have one of these for each attribute:
    [newObject setValue:[sInstance valueForKey:@"number"] forKey:@"number"];

    [manager associateSourceInstance:sInstance withDestinationInstance:newObject forEntityMapping:mapping];
    return YES;

@end

在持久协调器中,我已将 NSInferMappingModelAutomaticallyOption 更改为 NO,如下所示,

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 

    if (persistentStoreCoordinator != nil) 
        return persistentStoreCoordinator;
    

    NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"CoreDataMigrationPolicty.sqlite"];

    NSURL *storeUrl = [NSURL fileURLWithPath:storePath];

    NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
    [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
    [options setObject:[NSNumber numberWithBool:NO] forKey:NSInferMappingModelAutomaticallyOption];

    NSError *error = nil;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error])
    
        //NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    

    return persistentStoreCoordinator;

做完所有这些事情后,我收到了类似“Error Domain=NSCocoaErrorDomain Code=134110”(null)" UserInfo=NSUnderlyingException=Couldn't create mapping policy for class named (CoreDataMigrationPolicty.SampleMigrationV1toV2) with userInfo 字典之类的错误

未创建/调用映射模型。更改核心数据中的属性数据类型是否正确?有没有其他方法可以在不崩溃/重新安装应用程序的情况下解决此问题。

【问题讨论】:

轻量级迁移是最好的方法,如果你想在应用程序中添加属性并填充数据库。但是您无法更改数据类型,因为有不同的内部 sqlite 方法来存储字符串和数字,显然它们无法映射。如果数据不重要或应用程序尚未发送到生产环境,您可以从更新的模型创建新的托管对象,并创建新的 .sqlite 数据库而不是旧的。否则,只需使用名为 string_number 的迁移添加另一个实体,然后编写代码,将现有值从 number 复制到 string_number 【参考方案1】:

最后我发现我从这个答案中所做的错误。 Core Data Migration: Attribute Mapping Value Expression

问题在于我在映射模型属性中提到的表达式。 语法是 FUNCTION($entityPolicy, "convertNumberToString:" , $source.number) 函数定义是这样的

#import "SampleMigrationV1toV2.h"

@implementation SampleMigrationV1toV2

-(NSString *)convertNumberToString:(NSNumber *)number
    return  [number stringValue];

@end

FUNCTION($entityPolicy, "convertNumberToString:" , $source.number) :

$entityPolicy 获取我们在EntityMapping“SampleToSample”中提到的对应的MappingPolicy(即SampleMigrationV1toV2)和函数“convertNumberToString:”通过取输入值$source.Number将数字迁移到字符串

【讨论】:

这里是示例项目github.com/nmohankumarcse/CoreDataMigrationPolicySample

以上是关于在 CoreData 实体中将属性从 NSNumber 转换为 NSString - LightWeightMigration的主要内容,如果未能解决你的问题,请参考以下文章

Swift/IOS/CoreData:如何在自动生成的 CoreData 类中将 var 定义为枚举类型?

如何在 Swift 中将可转换属性保存到 Core Data

从实体中删除属性后迁移 CoreData 时出错

CoreData 迁移和数据映射:从现有属性创建新实体

使用 CoreData 以编程方式创建实体/表,并在 Swift 3 for iOS 中将值插入该实体

如何从 CoreData 实体获取结果