где реализовать Core Data?

Я совершенно новичок в программировании основных данных. я просто пытаюсь найти лучшее место для реализации кода основных данных. Я сделал учебник «Местоположение» для Apple, и он сработал хорошо. Теперь я пытаюсь перенести это в свой текущий проект, что немного сложнее.

в учебнике Locations показан один RootViewController, включая программно созданный tableView. мой проект основан на шаблоне tabView. ему принадлежит MainWindow.xib, включая TabBarController, включая три ViewController (MapView, ListView, SettingsView), где каждое представление имеет свой собственный navigationController и xib-файл.

Первым камнем преткновения было изменение кода, который он будет запускать с xib для tableView вместо его программного создания. Мне это удалось, но есть еще одна ошибка. Я не могу подключить managedObjectContext из appDelegate к listViewController. Я пробовал примеры и предложения по этой проблеме с этого форума здесь. но это все еще не работает.

посмотрев на образец проекта CoreDataBooks, я увидел, что код основных данных также был реализован в RootViewController. Похоже, это был бы неправильный способ реализовать это в ListViewController. Но в моем проекте нет RootViewController. В AppDelegate я напрямую передаю tabBarController как rootViewController. поэтому я не знаю, как добраться до listViewController для установки контекста, как это было сделано в примере Locations.

Поскольку MapView - это первое представление, я не могу установить контекст в appDelegate. И после долгой борьбы с managedObjectContext я задаюсь вопросом, не лучше ли изобрести RootViewController, чтобы иметь возможность размещать там дополнительный код. модель должна быть доступна для всех трех представлений, и кажется, что RootViewController - правильное место.

Но как мне совместить это с tabBarController, который включает еще три viewController на основе xib-файлов? Может ли кто-нибудь порекомендовать мне примеры или учебные материалы, включающие основные данные на основе приложения с панелью вкладок?


person rockstarberlin    schedule 11.07.2011    source источник
comment
Приложение, над которым я сейчас работаю, использует Core Data с архитектурой на основе tabBarController, поэтому я чувствую, что могу дать несколько советов. Что именно вы хотите делать? Перенести ваш контекст на разные вкладки?   -  person justin    schedule 11.07.2011
comment
точно. я только что исправил свою ошибку. Я могу взять контекст из appDelegate внутри viewDidLoad в ListViewController. К сожалению, мне не разрешено размещать здесь код, так как у меня ›100 сообщений. но завтра опубликую изменения. в любом случае я не уверен, что это обычный способ   -  person rockstarberlin    schedule 11.07.2011
comment
Я не совсем уверен, есть ли обычный способ. Я лично решил создать оконное приложение с Core Data. Затем в делегате приложения я создал IBOutlets для своего tabBarController и его вкладок, а затем синтезировал их в файле .m. Затем вы можете установить tab1.managedObjectContext = self.managedObjectContext, который передает ваш контекст выбранным представлениям. Вы должны настроить выходы в IB, а затем использовать [self.window addSubview:tabBarController.view] и [self.window makeKeyAndVisible]. Если у вашего метода есть проблемы, я буду рад поделиться более подробной версией   -  person justin    schedule 11.07.2011
comment
возможный дубликат Где разместить основной стек данных в приложении Cocoa / Cocoa Touch   -  person Brad Larson    schedule 11.07.2011
comment
кажется, так! как я могу закрыть эту ветку?   -  person rockstarberlin    schedule 11.07.2011


Ответы (4)


Прочтите следующую статью Маркуса Зарры: Передача NSManagedObjectContext в iOS. Это должно дать вам представление о том, как решить вашу проблему.

В общем, вы должны добавить свойство NSManagedObjectContext ко всем вашим ViewController и передать контекст, прежде чем добавлять их в стек представления через pushViewController:animated:. Вы не должны брать контекст из делегата вашего приложения.

Если вы передадите один NSManagedObject в ViewController, например чтобы представить своего рода подробное представление, вы можете получить доступ к контексту из этого объекта, поскольку каждый NSManagedObject знает о NSManagedObjectContext, в котором он «живет».

Если вы зарегистрированный разработчик iOS, я бы также порекомендовал видео WWDC 2010 и 2011. Есть несколько сессий по освоению Core Data.

person Florian Mielke    schedule 11.07.2011
comment
Спасибо за ваш ответ. я уже прочитал статью. поскольку автор упоминает, что он не делал этого с IB, информации не так много. я пробовал что-то вроде - ›self.tabBarController.listViewController.navController.managedObjectContext = context; - ›но это не сработало - person rockstarberlin; 11.07.2011

хорошо, теперь у меня есть правильное решение. потребовалось время, чтобы понять, но теперь он работает с внедрением зависимостей из делегата приложения в контроллеры представления (listViewController).

Моя проблема заключалась в том, что я не знал, как ссылаться на свои контроллеры представления, поскольку они вложены в выделенные navController и один tabBarController.

прочитав здесь много сообщений, я понял, что должен объявить свои контроллеры представления в appDelegate.h и синтезировать их в appDelegate.m, а затем подключить их к соответствующему элементу в IB. это было сделано быстро и легко после понимания :-)

rootViewController не нужен.

MyAppDelegate.h:

#import <UIKit/UIKit.h>
#import "ListViewController.h"

@interface MyAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {

    UIWindow *window;
    UITabBarController *tabBarController;
    IBOutlet ListViewController *listViewController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
@property (nonatomic, retain) IBOutlet ListViewController *listViewController;

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

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

@end

MyAppDelegate.m:

#import "MyAppDelegate.h"
#import "ListViewController.h"

@implementation MyAppDelegate

@synthesize window=_window;

@synthesize tabBarController=_tabBarController;

@synthesize managedObjectContext=__managedObjectContext;

@synthesize managedObjectModel=__managedObjectModel;

@synthesize persistentStoreCoordinator=__persistentStoreCoordinator;

@synthesize listViewController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    NSManagedObjectContext *context = [self managedObjectContext];

    if (!context) {
        // Handle the error.
    }
    // Pass the managed object context to the view controller.
    listViewController.managedObjectContext = context;

    // Override point for customization after application launch.
    // Add the tab bar controller's current view as a subview of the window
    self.window.rootViewController = self.tabBarController;

    [self.window makeKeyAndVisible];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];  
    return YES;
}

...

ListViewController.h

#import <CoreLocation/CoreLocation.h>


@interface ListViewController : UITableViewController <CLLocationManagerDelegate> {

    UINavigationController *navController;
    NSManagedObjectContext *managedObjectContext;
}

@property (nonatomic, retain) IBOutlet UINavigationController *navController;
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

-(NSManagedObjectContext *)managedObjectContext;

@end

ListViewController.m

#import "MyAppDelegate.h"
#import "ListViewController.h"


@implementation ListViewController

@synthesize navController;
@synthesize managedObjectContext;

- (void)viewDidLoad {

    [super viewDidLoad];

    NSLog(@"managedObjectContext: %@",[self managedObjectContext]);

    NSError *error = nil;
    if (![managedObjectContext save:&error]) {
        NSLog(@"error: %@",[self managedObjectContext]);
        return;
    }

...
person rockstarberlin    schedule 13.07.2011

Некоторое время назад я написал подобное приложение. Я решил это так: я сделал синглтон, у которого было свойство persistentStoreCoordinator, подобное тому, что указано в документации Apple, для хранения доступа к базе данных (так что мне не нужно писать его каждый раз). Затем в каждом контроллере представления панели вкладок я инициировал свой собственный NSManagedObjectContext.

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

Таким образом, каждый контроллер обращается к базе данных со своим собственным контекстом, если вы понимаете, о чем я.

Обратите внимание, что если какой-либо из ваших контроллеров представления имеет контроллер подробного представления, воспользуйтесь стандартным подходом для передачи ему контекста управляемого объекта, как в примере кода (Книги, Расположение, Рецепты).

person Dunja Lalic    schedule 11.07.2011
comment
спасибо за ваш anser! в книгах и местах они оба передают контекст RootViewController. в Книгах в topViewController. Похоже, в моем случае это был бы MapViewController. У вас есть идея, как я могу передать контекст в listViewController после нажатия на значок списка перед загрузкой listView? - person rockstarberlin; 11.07.2011
comment
Вы добавляете свойство managedObjectContext в listViewController, и когда хотите что-то с ним сделать, вы пишете что-то вроде этого: ListViewController *listViewController = [[ListViewController alloc] init]; listViewController.managedObjectContext = self.managedObjectContext; //present it [listViewController release];. Какое-то время я собирался написать об этом учебник, но, полагаю, я был слишком ленив. - person Dunja Lalic; 11.07.2011
comment
хорошо, я знаю, как это сделать, когда представляю viewController вручную. но в моем случае ListView будет отображаться после взаимодействия с кнопкой панели касаний. три моих представления контролируются tabBarController и создаются с помощью IB. я мог бы поместить что-нибудь в - ›tabBarController didSelectViewController, но я не уверен, инициализирован ли ListViewController уже или нет. или я могу создать его в любом случае в appDelegate, даже если он определен внутри tabBarController в IB? Разве это не другая ссылка, если ListViewController не является одноэлементным? - person rockstarberlin; 12.07.2011
comment
Мне очень жаль, но я не могу вам с этим помочь. Я всегда все делаю проблемно и не имею большого опыта работы с перьями. - person Dunja Lalic; 15.07.2011

я только что исправил ошибку. Я пропустил некоторые методы, необходимые в appDelegate. теперь он работает, если я помещаю следующий код в viewDidLoad моего ListViewController

if (managedObjectContext == nil) { 
    NSLog(@"managedObjectContext is nil");
    managedObjectContext = [(IntraAppAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}

это нормально относительно правильных правил шаблона MVC? в моем случае ViewController теперь берет контекст из appDelegate.

попытка установить контекст в appDelegate с чем-то вроде этого вызывает ошибку:

 NSManagedObjectContext *context = [self managedObjectContext];

    if (!context) {
        // Handle the error.
    }
    // Pass the managed object context to the view controller.

    self.tabBarController.listViewController.navController.managedObjectContext = context;
    self.window.rootViewController = self.tabBarController;

как я могу собрать ссылку на другие viewController, которые контролируются tabBarController и не являются topView / superView после запуска приложения? первое представление - это MapView. мне нужно создать или объявить listViewController в appDelegate? как его следует закодировать, чтобы он относился к listViewController, управляемому tabBarController?

person rockstarberlin    schedule 12.07.2011
comment
моя структура представления выглядит так: i5.photobucket.com / альбомы / y154 / rockstar_berlin / iOS / - person rockstarberlin; 12.07.2011