尝试从 iOS 中的 Singleton 类初始化 ManagedObjectContext

Posted

技术标签:

【中文标题】尝试从 iOS 中的 Singleton 类初始化 ManagedObjectContext【英文标题】:Trying to initialize ManagedObjectContext from Singleton class in iOS 【发布时间】:2013-09-25 22:15:24 【问题描述】:

我在 ios 中创建了一个单一视图应用程序,它还包含核心数据。我将我的 .xcdatamodel 文件从另一个应用程序移到了我现在正在处理的应用程序中,但我遇到了问题。我所做的是从之前的应用程序中剪切并粘贴代码并将其放在我的 AppDelegate.h/m 文件中:

@interface DBAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;

@end

还有我的 .m 文件:

    @implementation DBAppDelegate

    @synthesize managedObjectContext = _managedObjectContext;
    @synthesize managedObjectModel = _managedObjectModel;
    @synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    
        // Override point for customization after application launch.
        UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
//the line below is what is causing an error
        DBViewController *controller = (DBViewController *)navigationController.topViewController;
        controller.managedObjectContext = self.managedObjectContext;


        return YES;
    

在我的 .m 文件中,我还包含了 Core Data 的样板代码,该代码也在我之前的应用程序中,但我没有发布。在我的新应用程序中,我正在做的是创建了一个访问层,它还提供了一个 Singleton 实例来访问该层。我在这个类中进行 CRUD 操作,并在 .h 文件中声明了以下属性:

@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;

目前,我收到以下错误:

“在“DBViewController”类型的对象上找不到属性“managedObjectContext”。我想做的是在我的方法中初始化 managedObjectContext,以允许创建单例实例:

static DB *sharedSingleton = nil;

+ (DB *) sharedInstance 

    if (sharedSingleton == nil) 

        sharedSingleton = [[super alloc] init];

  

    return sharedSingleton;

我做错了什么?我意识到我没有在我的 DBViewController 中声明 managedObjectContext 对象,但是我应该用什么来代替这一行?我认为这与我的 Singleton 课程有关,但老实说,我对此一无所知。

【问题讨论】:

syedfa,在决定采用单例方法之前,请考虑阅读这篇文章Core Data singleton manager?。决定内存使用和线程的指标 【参考方案1】:

您尝试做的通常被称为“数据存储”单例,这是一种很好的设计模式。我在我的应用程序中做的是有一个名为DataStore 的单例类,你可以随意调用它,使用类方法:

+ (id)sharedStore
    static DataStore *sharedStore = nil;
    if (!sharedStore) 
        sharedStore = [[self alloc] init];
    

    return sharedStore;

每当我需要访问数据存储提供的资源时,我都会这样做:

Datastore *ds = [Datastore sharedStore];

为了提供对 Core Data 的访问,我有一个数据存储方法:

+ (NSManagedObjectContext*)managedObjectContext
    static NSManagedObjectContext *context = nil;

    if(context)
        return context;
    

    NSPersistentStoreCoordinator *coordinator = nil;

    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
    NSManagedObjectModel *objectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

    if (!coordinator) 
        coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:objectModel];
    

    if(!coordinator)
        return nil;
    

    NSString *storePath = [[self documentsDirectoryPath] stringByAppendingPathComponent:@"datastore.sqlite"];
    NSURL *storeURL = [NSURL URLWithString:storePath];

    NSError *error;

    if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:NULL error:&error])
    
        NSLog(@"Database error: %@", error);
        // if you make changes to your model and a database already exists in the app
        // you'll get a NSInternalInconsistencyException exception. When the model is updated
        // the databasefile must be removed. Remove the database here because it's easy.
        NSFileManager *fileManager = [NSFileManager defaultManager];
        [fileManager removeItemAtURL:storeURL error:nil];

        //try to add the persistant store one more time. If it still fails then abort
        if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:NULL error:&error])
            return nil;
    

    context = [[NSManagedObjectContext alloc] init];
    [context setPersistentStoreCoordinator:coordinator];
    [context setUndoManager:nil];

    return context;


如果无法创建 NSManagedObjectContext,则此方法返回 nil。这样你只需要这样做:

NSManagedObjectContext *context = [[DataStore sharedStore] managedObjectContext];

当您需要使用 Core Data 时。这可以在viewDidLoad 中完成一次。

编辑:

managedObjectContext方法使用下面的方法来查找文档目录:

+ (NSString *)documentsDirectoryPath

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
    return basePath;

【讨论】:

非常感谢您的及时回复。我使用了您的解决方案,但出现错误:选择器“documentsDirectoryPath”没有已知的类方法。我收到以下错误: NSString storePath = [[self documentsDirectoryPath] stringByAppendingPathComponent:@"datastore.sqlite"];我把这个方法 + (NSManagedObjectContext)managedObjectContext 放在我的 DataStore 类中,对吗? 查看我的编辑。我忘记了我使用一种方法来查找文档目录。 再次感谢您的及时回复。我现在收到 RuntimeException: 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter search for entity name'User'。在我的 DataStore 类中,我有方法 addUser,在该方法中我有以下几行: NSManagedObjectContext *context = [[DB sharedInstance] managedObjectContext];//我把这一行放在这里而不是 viewDidLoad 方法。用户 *user = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:context]; 作为后续问题,我是否仍需要 AppDelegate 类中的所有样板代码,还是可以完全删除它?只是想知道。 再次感谢。我意识到我的问题是我的 .sqlite 文件丢失了,我必须生成它。您的解决方案帮助我解决了我得到的原始问题,这就是我选择您的答案的原因。我的代码现在可以工作了:-)

以上是关于尝试从 iOS 中的 Singleton 类初始化 ManagedObjectContext的主要内容,如果未能解决你的问题,请参考以下文章

JS设计模式---单例(Singleton)模式

如何在TypeScript中定义Singleton

android中所有活动的单socket.IO连接

与PDO和Singleton类的数据库连接

Singleton类无法找到ctor,但编译,运行并保留实例未初始化

C++之单例(singleton)模式