Import AppDelegate into models?

I'm trying to unify all of my functions of a specific class within the model file. For instance, I would have a function fetchContactWithName:(NSString *)name in the model 'Contact.h/Contact.m', which my viewcontroller would subsequently call.

In this case, would it be a bad idea to import the AppDelegate.h file into the model file as a I need to access its managedObjectContext?

#import "AppDelegate.h"

@implementation Contact

...

+ (Contact *) fetchContactWithName:(NSString *) name {
  AppDelegate *delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];

  NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
  NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contact" inManagedObjectContext:delegate.managedObjectContext];
  [fetchRequest setEntity:entity];

  NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", name];
  [fetchRequest setPredicate:predicate];

  NSError *error = nil;
  NSArray *fetchedObjects = [delegate.managedObjectContext executeFetchRequest:fetchRequest error:&error];

  Contact *fetchedContact;
  for(Contact *contact in fetchedObjects) {
      fetchedContact = contact;
  }

  if(fetchedContact != nil) {
      return fetchedContact;
  } else {
      return nil;
  }

}
@end

In my opinion it's a bad idea to directly ask a different class to get your managed object context. Because

  • You can't really reuse your classes in different projects (think OS X app)
  • You can't fetch contacts in a different context (think background import)
  • You can't use unit tests if the method asks other class
  • You should tell this method in which context it should fetch.
    Instead of + (Contact *) fetchContactWithName:(NSString *) name your method signature should look like this:

    + (Contact *)fetchContactWithName:(NSString *)name inManagedObjectContext:(NSManagedObjectContext *)context
    

    each viewController should have a reference to the NSManagedObjectContext used in your app delegate. You can pass a reference of the context to each viewController in application:didFinishLaunchingWithOptions: , and each time you push or present a new viewController you pass the context instance to it.

    This might look like a lot of work now, but some day you will benefit from the "tell, don't ask" approach.


    I think, it is bad idea . Because it's OOP-ugly. What do I suggest? You should make a singleton class SharedStorage like this:

    + (SharedStorage*)sharedStorage
    {
        static SharedStorage* _sharedStorage = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _sharedStorage = [[self alloc] init];
        });
        return _sharedStorage;
    }
    
    - (SharedStorage*)init {
        self = [super init];
        if (self)
        {
            [self setupPersistentStoreCoordinator];
        }
        return self;
    }
    
    - (NSManagedObjectModel*)__managedObjectModel
    {
        if (_managedObjectModel_ == nil)
        {
            NSBundle *mainBundle = [NSBundle mainBundle];
            NSURL *modelURL = [mainBundle URLForResource:@"yourURL" withExtension:@"momd"];
            _managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        }
        return _managedObjectModel_;
    }
    
    
    - (void)setupPersistentStoreCoordinator
    {
        if (_storeCoordinator != nil)
            return;
        NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"YourDB.sqlite"];
        NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
        NSError *error;
        _storeCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self __managedObjectModel]];
        if (![_storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error])
        {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        }
    }
    

    And everywhere you want to use context you have to create a new NSManagedObjectContext with the same persistentStoreCoordinator :

    self.context = [NSManagedObjectContext new];
        self.context.persistentStoreCoordinator = [[SharedStorage sharedStorage] storeCoordinator];
    

    To access stuff's of AppDelegate class you need to

    In header file

    extern AppDelegate *appDelegate; 
    

    and in AppDelegate.m file

    AppDelegate *appDelegate = nil;
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
    }
    

    Now in Model view controller you import AppDelegate file and you can access its methods through its object.

    链接地址: http://www.djcxy.com/p/91648.html

    上一篇: 如何同步两个NSManagedObjectContext

    下一篇: 将AppDelegate导入模型?