6

Uso de guiones gráficos que no tienen fácil acceso al primer controlador de vista en AppDelegate (aunque una vez que lo prepareForSegue hace que sea fácil para pasar el ManagedObjectContext abajo de la pila de navegación.Pasando ManagedObjectContext para ver los controladores utilizando guiones gráficos con una UITabBarController raíz

me he decidido por dar a cada controlador de vista (o superclase de cada controlador de vista) que requiere de datos Básicos de acceder a un miembro moc:

@synthesize moc = _moc; 
@property (nonatomic) __weak NSManagedObjectContext *moc; 

estoy inquieto porque no parece una forma muy elegante de hacer es demasiado código. Pero asignarlo directamente requiere especificar inde absoluto equis en las matrices viewControllers y cambiar AppDelegate cada vez que el requisito para ManagedObjectContexts cambian

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController; 

    // rootView gets a tab bar controller 
    for(UINavigationController *navController in tabBarController.viewControllers) { 

     for(UIViewController *viewController in navController.viewControllers) { 

      if([viewController respondsToSelector:@selector(setMoc:)]) { 
       [viewController performSelector:@selector(setMoc:) withObject:self.managedObjectContext]; 
       NSLog(@"Passed moc to %@", [viewController description]); 
      } 
     } 
    } 

    return YES; 
} 

¿Cuáles son los peligros de este enfoque y es que hay una manera mejor? ¿Es mejor tratar de ser más genérico:

- (void)assignManagedObjectContextIfResponds:(UIViewController *)viewController { 

    if([viewController respondsToSelector:@selector(setMoc:)]) { 
     [viewController performSelector:@selector(setMoc:) withObject:self.managedObjectContext]; 
     NSLog(@"Passed moc to %@", [viewController description]); 
    } 

} 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    NSMutableArray *viewControllers = [NSMutableArray array]; 

    UIViewController *firstLevelViewController = self.window.rootViewController; 

    if([firstLevelViewController respondsToSelector:@selector(viewControllers)]) { 

     NSArray *firstLevelViewControllers = [firstLevelViewController performSelector:@selector(viewControllers)]; 

     for(UIViewController *secondLevelViewController in firstLevelViewControllers) { 

      if([secondLevelViewController respondsToSelector:@selector(viewControllers)]) { 

       NSArray *secondLevelViewControllers = [secondLevelViewController performSelector:@selector(viewControllers)]; 

       for(UIViewController *thirdLevelViewController in secondLevelViewControllers) { 

        [viewControllers addObject:thirdLevelViewController]; 
       } 

      } else { 
       [viewControllers addObject:secondLevelViewController]; 
      } 
     } 
    } else { 
     // this is the simple case, just one view controller as root 
     [viewControllers addObject:firstLevelViewController]; 
    } 

    // iterate over all the collected top-level view controllers and assign moc to them if they respond 
    for(UIViewController *viewController in viewControllers) { 
     [self assignManagedObjectContextIfResponds:viewController]; 
    } 

    return YES; 
} 

Respuesta

2

Adam,

Mientras estaba explorando guiones gráficos que hice más o menos de la misma manera que lo hizo, excepto que hice cada uno de mis controladores de vista que tenían una propiedad MOC se ajustan a un protocolo.

No hay nada significativamente diferente allí, así que seguiré adelante.

Creo que el punto es Storyboards, IMO, están medio cocidos. Procedente de un fondo .Net, lo que obviamente falta es una estructura de generador de objetos acoplada con un contenedor IoC. Cuando Apple agrega que Storyboards será increíble. Cuando el marco del guión gráfico puede ver el destinoViewController, determinar sus dependencias y resolverlas a partir de la vida útil de un contenedor será excelente. Por ahora, todo lo que realmente puede hacer es mirar el destinationViewController e iniciar uno genérico, que es de uso limitado.

Desafortunadamente, como es una solución a medias, sigo con el enfoque tradicional por ahora, así que todos mis controles de vista se asignan e inician manualmente y, lo que es más importante, agregué un método a cada controlador de vista para iniciar conMOC: (MOC *) moc;

El arquitecto en mí me está diciendo que este código es más robusto, supongo que es una cuestión de opinión si vale la pena el intercambio.

¿Alguien más viene con una mejor manera?

CA.

4

No sé si he entendido bien, pero ¿por qué no lo dejó el contexto objeto administrado directamente en la clase AppDelegate y dejar allí toda la lógica para instantiate. Y a partir de entonces puedes pedirlo.

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; 

luego puede recuperarlo en cualquier momento y desde cualquier lugar.

NSManagedObjectContext *moc = [(YourApplicationDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext]; 

Por conveniencia declarado definen para ello:

#define MOC [(YourApplicationDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext] 

Por lo tanto esto se convierta en:

[MOC save:&error]; 

Usted puede tomar esto en todas partes te gusta. Simplemente intente echarle un vistazo al código generado automáticamente para una aplicación CoreData en Xcode, verá que muchos accesadores con CoreData están ahí, y el CoreData en sí mismo se inicializa de forma lenta al solicitarlo por primera vez.

+1

Sé que puedes hacer eso pero estoy tratando de evitarlo. No se puede expresar claramente por qué está mal, pero se siente de esa manera, # importando AppDelegate en todas partes. –

+1

No está mal, es la forma de hacerlo, no tiene sentido pasar el contexto cuando puede acceder fácilmente. La importación solo es necesaria para evitar la advertencia del compilador (no error), porque siempre que puedas llamar a [UIApplication sharedApplication] desde cualquier lugar de tu código y funcione con la importación, esto es también lo que genera el Xcode para una aplicación CoreData, sorprende por qué declaras que está mal, y prefieres pasar el contexto de esa manera. Al centralizar los accesadores CoreData también obtiene más control para guardar el error, la carga diferida, lo que quiera. – Leonardo

+0

http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html "incorrecto" quizás no era la palabra correcta. Estoy buscando lo óptimo. –

Cuestiones relacionadas