El object es nulo cuando se llama desde otra class.

Quiero cambiar las properties de otro object, cuando se invoca un método en otra class.

El código para cambiar las properties de este object se encuentra en un método de la primera class y funciona al llamarlo desde su propia class, pero cuando se le llama desde la otra class, el object en el método devuelve nil.

Aquí está el código:

ViewController.h

@interface ViewController : UIViewController { UIView *menuView; //the object } @property (nonatomic, retain) IBOutlet UIView *menuView; -(void)closeMenu; //the method @end 

ViewController.m

 @implementation ViewController @synthesize menuView; -(void)closeMenu{ [menuView setFrame:CGRectMake(menuView.frame.origin.x, -menuView.frame.size.height, menuView.frame.size.width, menuView.frame.size.height)]; NSLog(@"%f", menuView.frame.size.height); //returns height when method is called from it's own class. But returns 0 (nil) when called from the other class. } 

SDNestedTableViewController.h (nada demasiado importante, pero ¿podría ayudar?)

 @interface SDMenuViewController : SDNestedTableViewController{ } 

SDNestedTableViewController.m

 #import "SDMenuViewController.h" #import "ViewController.h" - (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem { ViewController *firstViewController = [[[ViewController alloc] init] autorelease]; SelectableCellState state = subItem.selectableCellState; NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem]; switch (state) { case Checked: NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath); [firstViewController closeMenu]; //called from other class break; case Unchecked: NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath); break; default: break; } } 

EDIT 2:

Bueno, me enviaste tu código, así que ahora ya no puedo decir que no tengo suficiente información para resolver tu problema.

Veamos.

Ahora veo que su ViewController es el rootViewController de su aplicación, así:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; // Override point for customization after application launch. self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease]; self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; return YES; } 

Bien, ahora, ¿cómo se relaciona ViewController con su SDNestedTableViewController?

Tiene esto en la vista ViewControllerDidLoad:

 - (void)viewDidLoad { [super viewDidLoad]; SDMenuViewController *mvc = [[[SDMenuViewController alloc] initWithNibName:@"SDNestedTableView" bundle:nil] autorelease]; [self addChildViewController:mvc]; [mvc didMoveToParentViewController:self]; [menuView addSubview:mvc.view]; // Some other stuff with gesture recognizers I'm omitting... [self openMenu]; } 

Muy bien, por lo que parece que SDMenuViewController es hijo de ViewController. Ahora, tiene un método en SDMenuViewController llamado elemento: subItemDidChange:

 - (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem { ViewController *firstViewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease]; SelectableCellState state = subItem.selectableCellState; NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem]; switch (state) { case Checked: NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath); //close the menuView [firstViewController closeMenu]; break; case Unchecked: NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath); break; default: break; } } 

Entonces, desea que la reference vuelva al object ViewController existente , ¿verdad? Porque ahí mismo estás haciendo otro. Entonces, puedes hacer esto:

 ViewController *firstViewController = self.parentViewController; 

Eso te hace una reference al padre de SDMenuViewController, que es la instancia de ViewController. Esta propiedad se establece cuando haces tu addChildViewController: llamada.


De acuerdo, esto es confuso:

En su publicación, dice que su item:subItemDidChange: method está en SDNestedTableViewController, pero en el código que me envió está en SDMenuViewController.

En el SDNestedTableViewController, encontré este método:

 - (void) mainItem:(SDGroupCell *)item subItemDidChange: (SDSelectableCell *)subItem forTap:(BOOL)tapped { if(delegate != nil && [delegate respondsToSelector:@selector(item:subItemDidChange:)] ) { [delegate performSelector:@selector(item:subItemDidChange:) withObject:item withObject:subItem]; } } 

Parece que no estás usando el mismo código que en la publicación original, pero lo suficientemente cerca, lo que sea.


Ahora, si desea get una reference a la instancia ViewController desde cualquier lugar de la aplicación, no solo su SDMenuViewController (que es el elemento secundario de la instancia ViewController), debe utilizar la respuesta de @Mathew Varghese.

Aquí hay una actualización de este método:

  1. Agregue la + (AppDelegate *)instance; line + (AppDelegate *)instance; a su file AppDelegate.h.
  2. Agregue el siguiente método a su file AppDelegate.m.

Al igual que:

 + (AppDelegate *)instance { AppDelegate *dg = [UIApplication shanetworkingApplication].delegate; return dg; } 

Entonces, en cualquier object que desee esa reference, usted #import AppDelegate.h y dice ViewController *vc = AppDelegate.instance.firstViewController;

De todos modos, es solo otra forma de decir lo que Mathew mencionó anteriormente.

Lo que publicaste parece:

 -(void)closeMenu{ // menuView is never initialized, == nil [nil setFrame:CGRectMake(0, -0, 0, 0)]; NSLog(@"%f", 0); //returns height when method is called from it's own class. But returns 0 (nil) when called from the other class. } 

Entonces estás haciendo NSLog(@"%f", 0); .

Si carga la vista accediendo a la propiedad de view , el menuView será inicializado por las reglas de IB. Para ver los detalles de la carga / descarga de viewController ver los documentos de reference .

Creo que esto puede ayudarte.

En la class AppDelegate , debe declarar un object de la class ViewController . Hazlo como una propiedad de la class YourAppDelegate . como abajo. (Esto importaría la class ViewController y creará un object compartido de class YourAppDelegate para que pueda acceder a los miembros de la class YourAppDelegate globalmente simplemente importando YourAppDelegate.h ).

 #import "ViewController.h" #define UIAppDelegate ((YourAppDelegate *)[UIApplication shanetworkingApplication].delegate) @interface YourAppDelegate : NSObject <UIApplicationDelegate> { ViewController *objViewController; } @property (nonatomic, retain) ViewController *objViewController; @end 

Y sintetice la propiedad en el file YourAppDelegate.m .

 @implementation YourAppDelegate @synthesize objViewController; @end 

Entonces, la parte complicada es que debe hacer una copy de security del object de la class ViewController en la class YourAppDelegate en el momento en que carga la class ViewController .

Para que primero importe el YourAppDelegate.h en la class ViewController.h y en el ViewController.m implementar viewWillAppear: delegue de la siguiente manera.

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; UIAppDelegate.objViewController = self; } 

Luego en SDNestedTableViewController.m ,

 #import "SDMenuViewController.h" #import "ViewController.h" - (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem { ViewController *firstViewController = (ViewController *)UIAppDelegate.objViewController; if(firstViewController && [firstViewController isKindOfClass:[ViewController class]]) { SelectableCellState state = subItem.selectableCellState; NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem]; switch (state) { case Checked: NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath); [firstViewController closeMenu]; //called from other class break; case Unchecked: NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath); break; default: break; } } } 

Pruebe de esta manera. No digo esto como el path correcto, pero esto debería funcionar. Me alegra que esto te ayude.

el problema es:

 - (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem { ViewController *firstViewController = [[[ViewController alloc] init] autorelease]; ... [firstViewController closeMenu]; } 

Cuando llama a closeMenu desde allí, nunca se inicializa, porque no ha pasado suficiente time para inicializar la view del controller de vista, viewDidLoad se viewDidLoad método viewDidLoad de su firstViewController en este punto. menuView tampoco se crea desde la punta, así que esta es la razón por la que es nil .

Tal vez por alguna razón pueda haber un retraso lo suficientemente largo para que se menuView , pero no es así como deberías hacer cosas en iOS.

Por lo tanto, si no desea mostrar su menuView , simplemente agregue un valor boolean a su firstViewController y en lugar de closeMenu do:

 firstViewController.shouldCloseMenu = YES; 

Luego, en su ViewController en el método viewDidLoad , haga algo como:

 if (self.shouldCloseMenu ) { [self closeMenu]; } 

Tal vez esta no sea la mejor manera de hacerlo, pero ahora tienes una idea de cómo supone que funciona.

Creo que su problema está relacionado con la forma en que ha inicializado viewController.

En lugar de

 ViewController *firstViewController = [[[ViewController alloc] init] autorelease]; 

utilizar

 ViewController *firstViewController = [[[ViewController alloc] initWithNibName:@"yourNibName" bundle:nil] autorelease]; 

Asumo que tienes una punta porque estás usando un IBOutlet. Pero creo que IBOutlet nunca está configurado porque no ha cargado el file nib.

También verifique doblemente su connection IBOutlet con el creador de la interfaz y use "self.menuView"

Te sugiero que resuelvas este problema en los siguientes pasos.

  1. No utilice ninguna instancia o variable de firstViewController en SDMenuViewController .

  2. En el bloque de comprobación de casos, publique un post en NSNotificationCenter

  3. En el ViewController registre el post con el mismo Id de post, use el método closeMenu como su manejador.

Para mí, usar el centro de posts para enviar el manejo puede desacoplar la relación entre los controlleres. Esta es una mejor manera de preocuparse less por el ciclo de vida del controller dentro de otro.

Espero que sea de ayuda.

Existe una diferencia entre la alloc-init de un ViewController y la alloc-init de las properties del controller de vista.

Con respecto a su segundo ejemplo (llamar desde otra class). Su código actual indica que alloc-init firstViewController, pero luego no hace nada con él. Suponiendo que no haya anulado el método init de ViewController, sus properties e iVars deberían ser nil (o indefinidas en el peor de los casos). alloc-init debe alloc-init su firstViewController.menuView . Es decir:

 firstViewController.menuView = [[UIView alloc] initWithFrame]; // Don't do this. 

El problema con este enfoque es que está configurando las properties de firstViewController de otra class, y en general es una práctica de layout bastante promedio. Esta configuration requerida normalmente ocurriría en viewDidLoad pero como aún no ha hecho nada con firstViewController, nunca se llama.

Por el contrario, cuando llamas a closeMenu desde su propio controller de closeMenu , las probabilidades son que realmente estás haciendo algo con la vista y viewDidLoad (o donde menuView = [[UIView alloc] init]; se encuentra primero), inicializando tu menuView object.

Debe asegurarse de que su object menuView se inicialice antes de intentar y hacer algo con él, solo inicializar el controller de vista que contiene no es suficiente.

 #import "SDMenuViewController.h" #import "ViewController.h" - (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem { 

// ¿Por qué estamos asignando este object aquí, si solo se requiere en caso de verificación:

  ViewController *firstViewController = [[[ViewController alloc] init] autorelease]; SelectableCellState state = subItem.selectableCellState; NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem]; switch (state) { case Checked: NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath); [firstViewController closeMenu]; //called from other class break; case Unchecked: NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath); break; default: break; } } 

Cambiarlo por

 #import "SDMenuViewController.h" #import "ViewController.h" - (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem { 

// ¿Por qué estamos asignando este object aquí, si solo se requiere en caso de verificación:

  SelectableCellState state = subItem.selectableCellState; NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem]; switch (state) { case Checked: NSLog(@"Changed Sub Item at indexPath:%@ to state \"Checked\"", indexPath); // here no need to put object in autorelease mode. ViewController *firstViewController = [[ViewController alloc] init]; [firstViewController closeMenu]; //called from other class [firstViewController release]; break; case Unchecked: NSLog(@"Changed Sub Item at indexPath:%@ to state \"Unchecked\"", indexPath); break; default: break; } } 

intente eliminar UIView * menuView; // el object del file de interfaz

 @interface ViewController : UIViewController { // try to remove this line UIView *menuView; //the object } 

y actualice este método

 -(void)closeMenu{ [self.menuView setFrame:CGRectMake(self.menuView.frame.origin.x, -self.menuView.frame.size.height, self.menuView.frame.size.width, self.menuView.frame.size.height)]; NSLog(@"%f", self.menuView.frame.size.height); } 

Todo es correcto, cambie el método – (void) closeMenu como …

 -(void)closeMenu { menuView=[[UIView alloc]initWithFrame:CGRectMake(50.0,50.0,200.0,200.0)] NSLog(@"%f", menuView.frame.size.height); //returns height when method is called from it's own class. But returns 0 (nil) when called from the other class. } 

Intenta eso y dejame saber.

Sugiero que use esto:

 if(menuView) { [menuView setFrame:CGRectMake(menuView.frame.origin.x, -menuView.frame.size.height, menuView.frame.size.width, menuView.frame.size.height)]; } else { NSLog(@"menuView is nil"); }