iOS - 轻量级迁移 - 未识别选择器

3
我正在尝试进行轻量级迁移。我按照这个教程一步一步地制作了一个新的项目,并且一切都正常工作。但是现在我在另一个应用程序中,一切似乎都很顺利,但当我尝试访问新字段时,我会收到以下错误提示。
[Promocion setEnlace:]: unrecognized selector sent to instance 0x7fafe40bceb0

我已经选择了正确的模型。 输入图像描述 这是模型Promocion.h。
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

/*
@interface Promocion : NSManagedObject

@property (nonatomic, retain) NSNumber * id_promocion;
@property (nonatomic, retain) NSString * descripcion;
@property (nonatomic, retain) NSString * titulo;
@property (nonatomic, retain) NSString * url;
@property (nonatomic, retain) NSString * fecha_inicio;
@property (nonatomic, retain) NSString * fecha_fin;

@end
 */

NS_ASSUME_NONNULL_BEGIN

@interface Promocion : NSManagedObject

// Insert code here to declare functionality of your managed object subclass

//+(id)personaWithContext:(NSManagedObjectContext *)context;

@end

NS_ASSUME_NONNULL_END

#import "Promocion+CoreDataProperties.h"

Promocion.m

#import "Promocion.h"


@implementation Promocion


- (NSComparisonResult)compare:(Promocion *)otherObject {

    NSDateFormatter *dateformat = [[NSDateFormatter alloc] init];
    [dateformat setDateFormat:@"MMMM dd,eeee HH:mm a z"];
    NSDate *dateA = [dateformat dateFromString:self.fecha_inicio];
    NSDate *dateB = [dateformat dateFromString:otherObject.fecha_inicio];

    return [dateA compare:dateB];
}

@end

以下是自动生成的文件: Promocion+CoreDataProperties.h
#import "Promocion.h"

NS_ASSUME_NONNULL_BEGIN

@interface Promocion (CoreDataProperties)

@property (nullable, nonatomic, retain) NSString *descripcion;
@property (nullable, nonatomic, retain) NSString *fecha_fin;
@property (nullable, nonatomic, retain) NSString *fecha_inicio;
@property (nullable, nonatomic, retain) NSNumber *id_promocion;
@property (nullable, nonatomic, retain) NSString *titulo;
@property (nullable, nonatomic, retain) NSString *url;
@property (nullable, nonatomic, retain) NSString *enlace;

@end

NS_ASSUME_NONNULL_END

Promocion+CoreDataProperties.m #import "Promocion+CoreDataProperties.h"

Promotion+CoreDataProperties.m #import "Promotion+CoreDataProperties.h"

@implementation Promocion (CoreDataProperties)

@dynamic descripcion;
@dynamic fecha_fin;
@dynamic fecha_inicio;
@dynamic id_promocion;
@dynamic titulo;
@dynamic url;
@dynamic enlace;

@end

AppDelegate.m

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"data.sqlite"];

    //Migration
    NSDictionary *options = @{
                              NSMigratePersistentStoresAutomaticallyOption  :@YES,
                              NSInferMappingModelAutomaticallyOption        :@YES
                              };

    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                   configuration:nil
                                                             URL:storeURL
                                                        //options:nil
                                                         options:options//automatic migration
                                                           error:&error]) {
        /*
         Replace this implementation with code to handle the error appropriately.

         abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

         Typical reasons for an error here include:
         * The persistent store is not accessible;
         * The schema for the persistent store is incompatible with current managed object model.
         Check the error message to determine what the actual problem was.


         If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.

         If you encounter schema incompatibility errors during development, you can reduce their frequency by:
         * Simply deleting the existing store:
         [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]

         * Performing automatic lightweight migration by passing the following dictionary as the options parameter:
         @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES}

         Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.

         */
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        //abort();
    }

    return _persistentStoreCoordinator;
}

附加信息

我已更新项目的版本。

在哪里访问名为“enlace”的字段?

NSString* className = NSStringFromClass([Promocion class]);
NSEntityDescription *entity = [NSEntityDescription entityForName:className inManagedObjectContext:context];
Promocion* obj = (Promocion*)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:context];

obj.id_promocion = [NSNumber numberWithInt:[[centro objectForKey:@"id_promo"] intValue]];
obj.titulo = [centro objectForKey:@"titulo"];
obj.descripcion = [centro objectForKey:@"descripcion"];
obj.url = [centro objectForKey:@"imagen"];
obj.fecha_inicio = [centro objectForKey:@"fecha_ini"];
obj.fecha_fin = [centro objectForKey:@"fecha_fin"];
obj.enlace = [centro objectForKey:@"enlace"];

我尝试过的方法

我已经修改了Promocion.h以避免使用Promocion+CoreDataProperties.h,但仍然出现相同的错误。

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@interface Promocion : NSManagedObject

@property (nonatomic, retain) NSNumber * id_promocion;
@property (nonatomic, retain) NSString * descripcion;
@property (nonatomic, retain) NSString * titulo;
@property (nonatomic, retain) NSString * url;
@property (nonatomic, retain) NSString * fecha_inicio;
@property (nonatomic, retain) NSString * fecha_fin;
@property (nonatomic, retain) NSString * enlace;

@end

另一次尝试

我重新创建了Promocion.h,删除了旧的,并使用Editor->Create NSOjecteManaged子类创建了一个新的。看起来它正在工作。但是当我使用git回滚到最后一个未更新core data提交并在设备上安装它,然后升级应用程序到具有新coredata模型的最后提交时,它开始再次失败。该死,我感到非常沮丧。

Partial Appdelegate.m

#pragma mark - Core Data stack

// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
- (NSManagedObjectContext *)managedObjectContext
{
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _managedObjectContext;
}

// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)managedObjectModel
{
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"DataModel" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"data.sqlite"];

    //Migration
    NSDictionary *options = @{
                              NSMigratePersistentStoresAutomaticallyOption  :@YES,
                              NSInferMappingModelAutomaticallyOption        :@YES
                              };

    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                   configuration:nil
                                                             URL:storeURL
                                                        //options:nil
                                                         options:options//automatic migration
                                                           error:&error]) {
        /*
         Replace this implementation with code to handle the error appropriately.

         abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

         Typical reasons for an error here include:
         * The persistent store is not accessible;
         * The schema for the persistent store is incompatible with current managed object model.
         Check the error message to determine what the actual problem was.


         If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.

         If you encounter schema incompatibility errors during development, you can reduce their frequency by:
         * Simply deleting the existing store:
         [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]

         * Performing automatic lightweight migration by passing the following dictionary as the options parameter:
         @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES}

         Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.

         */
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        //abort();
    }

    return _persistentStoreCoordinator;
}

解决方案

最终出现问题的原因是我有两个Coredata文件的引用(不知道为什么)。其中一个仍然是第一个版本。我已经更改了那个版本,现在一切都按预期工作。


我会清理您的构建文件夹/删除派生数据,然后再试一次。 - sschale
@sschale,派生数据在哪里? - Ricardo
~/Library/Developer/Xcode/ - sschale
如果您包含尝试使用此新属性的代码,将会很有帮助。 - Tom Harrington
在Xcode的项目导航器打开的左侧,使用窗口左下角的搜索字段。 - Tom Harrington
显示剩余7条评论
4个回答

3
我认为你的错误与轻量级迁移无关,因为你的应用程序没有在启动时崩溃(对于任何没有迁移的结构更改),但是会提供与你的模型类主要相关的运行时错误。
我怀疑你的代码仍然使用旧的生成的模型类或旧类上的旧类别,而不带有缺少的属性:(#import "Promocion.h"#import "Promocion+creation.h")。
如果您的coreData & managedObjects子类是在Xcode 7之前的旧版本中创建的,则很可能是这种情况。一个简单的检查方法是cmd+tap在任何#import "Promocion.h"上以查看内容。
如果是这种情况,请按以下检查清单来解决问题(否则仍可帮助其他面临类似问题的人):
-搜索并删除(或重命名!)Promocion.h :仅包含动态属性的旧生成文件(使用Xcode7版本之前的版本生成,请参见下面的详细信息)。
-检查是否在该类上创建了一个类别.."Promocion+Xyz.h"并将所有引用#import "Promocion+Xyz.h"更改为#import "Promocion.h"
-重新创建您的managedObject子类。
背景:
在Xcode7之前,每当我们创建一个managedObject子类时,.h文件包含动态属性,并且我们使用一个类别在该类上添加方法,同时能够重新生成我们的managedObject子类而不会丢失我们创建的方法,因为它们在类别中。
从Xcode7开始,Apple对此进行了审核,现在动态属性位于ClassName+CoreDataProperties.h中,以便轻松地在主类上工作/添加方法,无需添加类别,并且同时能够重新生成managedObject,因为只有ClassName+CoreDataProperties.h被重新创建。
因此,现在每当我们重新创建以前通过旧方式创建的managedObject子类时,我们需要确保引用正确的文件#import "Promocion.h"

请展示您的[self managedObjectModel]方法。如果您正在使用mergedModelFromBundles,请尝试更改为nitWithContentsOfURL:NSString *path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"];NSURL *url = [NSURL fileURLWithPath:path];NSManagedObjectModel *managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:url]; - Idali
我已经在问题中更新了AppDelegate的代码片段。你能否更新回答? - Ricardo
看起来你已经在使用initWithContentsOfURL:url而不是mergedModelFromBundles... - Idali
由于从DataModel.xcdatamodel迁移到DataModel2.xcdatamodel可以使用您当前的代码版本,但在旧代码版本中失败,请确保DataModel.xcdatamodel完全相同。您可以使用git diff进行检查。http://blog.chaitanyagupta.com/2012/05/git-diff-driver-for-core-data-model.html - Idali
我尝试使用mergedModelFromBundles,但是遇到了相同的错误(+[DataParser fetchPromos]) (DataParser.m:65) exception = -[Promocion setEnlace:]: unrecognized selector sent to instance 0x7fd2438b4b90 - Ricardo
显示剩余4条评论

0
最终出了问题的原因是我有两个Coredata文件的引用(不知道为什么)。其中一个仍然是第一个版本。我已经更改了那个版本,现在一切都按预期工作了。

0

看起来迁移没有发生,虽然类文件可能是正确的,但它们都依赖于底层的NSManagedObject属性。

您能否从已更新到Model 2的设备中获取sqlite文件,并检查sqlite文件的结构,看新属性是否已就位?如果没有,则说明迁移未触发,可能定义了错误版本的模型作为当前版本。


我怎样才能从iPhone获取SQLite? - Ricardo
将设备连接到运行Xcode的Mac上,然后在“设备”窗口中,您可以下载应用程序包的内容。在该包内部将会有sqlite文件。 - Marcus S. Zarra
我只在模拟器上进行测试。 - Ricardo
然后它将在您的应用程序支持目录中。请在此处查看答案:https://dev59.com/umAf5IYBdhLWcg3wwlC5 - Marcus S. Zarra

-1

尝试更改您的AppDelegate的datamodel函数中的行:

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"DataModel" withExtension:@"momd"];

使用

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"DataModel 2" withExtension:@"mom"];

这个不起作用,我收到了这条消息 CoreData: 无法加载NSManagedObjectModel。nil是非法的URL参数 - Ricardo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接