Values not passed back after dismissModalViewController - objective-c

I'm passing a string variable for the sake of testing (isLoggedIn) as well as an NSManagedObject (userObject). However, when I dismiss the VC and it comes back to the root, I do not have the new data that was set in the variables in the loginViewController.
LoginViewController *loginVC = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
loginVC.managedObjectContext = self.managedObjectContext;
loginVC.userObject = self.userObject;
loginVC.isLoggedIn = self.isLoggedIn;
[self presentModalViewController:loginVC animated:YES];
[loginVC release];
I later dismiss the view with:
[self dismissModalViewControllerAnimated:YES];
Update:
Ended up using delegates as someone suggested. I used the following post as a guideline:
UIViewController parentViewController access properties

I ended up using delegates as someone above suggested. I used the following post as a guideline:
UIViewController parentViewController access properties

I may not be following you properly so this could be irrelevant.
I am guessing you mean that:
You set your ivars after alloc/init
You make some changes inside LoginViewController
You expect those changes to be reflected in self.userObject and self.isLoggedIn of the class that instantiated LoginViewController
which may or may not happen if you act on the objects themselves or you reassign the pointers
e.g.
If you call self.userObject.name = #"Test"; inside LoginViewController then the change will be reflected in the class that instantiated LoginViewController and LoginViewController because the ivars are pointing to the same object in memory and you are manipulating the object.
OR
If you call self.userObject = theResultOfSomeNewFetch; then the change will not be reflected as you now have a pointer in LoginViewController that is pointing to a different userObject to the pointer in the class that called LoginViewController
Hopefully I have not lost the plot completely and this is somewhere near what you mean.

Related

Objective-C (iOS): prepareForSegue won't pass my data into destination VC

VC1 = NewGameViewController
VC2 = GameViewController
NewGameViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if( [segue.identifier isEqualToString:#"newGameSegue"]) {
GameViewController *gameVC = (GameViewController *)segue.destinationViewController;
NSArray *array = [self nameArrayForTextFieldArray:self.namePicker.textFieldArray withColon:YES];
gameVC.nameArray = [[NSArray alloc] initWithArray:array];
}
-(NSArray *)nameArrayForTextFieldArray:(NSArray *)array withColon:(BOOL *)bool
basically returns an nsarray of strings given an nsarray of textfields. withcolon is a bool of whether or not you want the strings to have a colon appended to the end.
when i debug my code, the _nameArray ivar in gameVC still reads nil after every line here is called...can anyone help me out here??
The prepareForSegue method is invoked by UIKit when a segue from one screen to another is about to be performed. It allows us to give data to the new view controller before it will be displayed. Usually you’ll do that by setting its properties.
The new view controller can be found in segue.destinationViewController. If GameViewController embed the navigation controller, the new view controller will not be GameViewController but the navigation controller that embeds it.
To get the GameViewController object, we can look at the navigation controller’s topViewController property. This property refers to the screen that is currently active inside the navigation controller.
To send an object to the new view controller you can use this solution using performSegueWithIdentifier:
For example, if we want to perform a segue pressing a UIButton we can do this:
In the MyViewController.h we create a IBAction (connected to UIButton), dragging the button from storyboard to code:
- (IBAction)sendData:(id)sender;
In MyViewController.m we implement the method:
- (IBAction)sendData:(id)sender
{
NSArray *array = [self nameArrayForTextFieldArray:self.namePicker.textFieldArray withColon:YES];
[self performSegueWithIdentifier:#"newGameSegue" sender:array];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"newGameSegue"]) {
UINavigationController *navigationController = segue.destinationViewController;
GameViewController *controller = (GameViewController *)navigationController.topViewController;
controller.nameArray = sender;
}
}
Is GameViewController embedded in a navigation controller? In that case, your destinationViewController property is of type UINavigationController, not GameViewController. You can get to GameViewController by calling [segue.destinationViewController.viewControllers lastObject].
I'm assuming that you've done a NSLog (or examine it in the debugger) of array immediately before setting gameVC.nameArray. You really want to make sure it's being set the way you think it is. It's amazing how many times I've spent debugging something like this only to realize the problem was in my equivalent to nameArrayForTextFieldArray. Or a typo in the name of the segue identifier. Or random things like that.
Assuming that's ok, then a couple of things are possible:
How is your nameArray property defined in GameViewController? If it's not a strong reference (or a copy), then when your array falls out of scope, it will be deallocated. I think this would manifest itself slightly differently, but it's worth confirming.
Also, I've seen situations where a controller like GameViewController might have some confusion between various ivars and properties (which is why I never define ivars for my properties ... I let #synthesize do that).
I assume you're not using a custom setter for nameArray. I just want to make sure. If so, though, please share that, too.
Bottom line, can you show us all references to nameArray in your #interface of GameViewController as well as in its #synthesize statement?

What happens after a viewController is pushed into another viewController

I was just wondering while programming. I have got a rootViewController which creates an instance of a childViewController. This childVC is pushed onto my rootViewController through [self.navigationController pushViewController:childVC] from another childViewController (say childVC2). Now I was wondering what happens with my instance of childVC2. Does it get released? Because when returning from childVC to childVC2 I create a new instance of childVC2 and push it into my rootViewController. Obviously I do not have any use for the earlier instance of childVC2 so what happens with it or haw can I manually release it?
Yes if you are alloc the ViewController you have to release it .. the push will increase its reference count by 1 so you have to be sure that you are pop it to decrase the reference count .. and for the creating the instance define it in .h and when create it do it like this
if(yourViewController)
[yourViewContoller release];
yourViewController = [yourViewControllerClass alloc] init];
another opition is to make it autorelease and in this case you are not responsible to release the ViewController
yourViewController = [yourViewControllerClass alloc] init]autorelease];

Delegate methods no longer called after converting to use Automatic Reference Counting

I've converted an app I'm writing to ios 5 and then using the inbuilt tool I converted it to use Automatic Reference Counting. There were no problems with ios 5 but after ARC conversion most of my delegate calls don't seem to be working. For example I have a subclass of UITableViewController with a .h file that looks like:
#interface UITableVCSubclass : UITableViewController <UITableViewDelegate, ... >
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
...
#end
The Table View Delegate method tableView:didSelectRowAtIndexPath: no longer gets called when I select a row of the table. If checked that self.tableview.delegate == self, which it does. Any ideas why this has stopped working?
I had the same issue and couldn't find a good reference so hopefully this will help someone else. My working project didn't work after running the ARC refactoring doohickey. The view controller for my UITableView was being created on the fly and pushed without saving a reference, which is not something the conversion process looks for.
ARC was releasing the vc when it fell out of scope, so the view was visible but its delegate was gone. To fix it I added a strong property to the super to hold a reference to the new view controller and then I started receiving events again.
Changed from this:
MyViewController *myViewController =
[[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
To using the new property:
self.myViewController =
[[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];

Overriding UITableViewController's cellForRowAtIndexPath in Objective-C

I have a view controller MainVC which contains a view where I want to switch between various tables. I have an "abstract" class called InfoVC which extends UITableViewController and contains several methods that must be overridden or else they throw an exception. Finally, I have several classes which extend InfoVC and implement the "abstract" methods in InfoVC, along with methods that override tableView's numberOfRowsInSection and cellForRowAtIndexPath.
This is how I load a table in MainVC. In this case, TemperatureInfoVC extends InfoVC, self.subVC is of type InfoVC, and switchView is a view in MainVC:
TemperatureInfoVC *sVC = [[TemperatureInfoVC alloc] initWithStyle:UITableViewStylePlain];
self.subVC = sVC;
[sVC release];
[switchView insertSubview:self.subVC.view atIndex:0];
My problem is that the table always loads empty. From setting breakpoints, I can see that TemperatureInfoVC's numberOfRowsInSection is being called, but neither TemperatureInfoVC's or InfoVC's cellForRowAtIndexPath are being called. However, if I change the first line in the code above to:
InfoVC *sVC = [[InfoVC alloc] initWithStyle:UITableViewStylePlain];
then InfoVC's numberOfRowsInSection and cellForRowAtIndexPath are called properly. Does anyone know why TemperatureInfoVC's cellForRowAtIndexPath is not being called?
I assume, that you are not setting the delegate (UITableViewDelegate) and the datasource (UITableViewDatasource). Usually the delegate and the datasource implementation are with-in the custom UITableViewController, so (if not wiring up in IB), there need to be this somewhere:
tableView.delegate = self;
tableView.dataSource = self;
often within the -loadView or -viewDidLoad:
Oops, figured it out. I was loading data from an NSMutableArray in TemperatureInfoVC which was set in MainVC, but I was setting the data before I initialized subVC, so of course the table had no data in it.

referencing an instantiated object in another class in objective C

I am working in xcode on an ipod app in objective C, and I have a field (navigationController) in one of my classes (rootViewController). How do I reference the instantiated rootViewController's navigationController from another class? For example, how would I do this if I want to reference the navigationController from the FirstViewController.m class?
I seem to only be able to find references for this to reference the application delegate.
If I want to reference the application delegate with FirstViewController, I just say:
MyAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[delegate.navigationController pushViewController:childController animated:YES];
how do I do this for the rootViewController class instead of MyAppDelegate?
Based on the question you are asking, it seems that you want to call methods on the UINavigationController that is higher up in the stack. All UIViewControllers already have a property of navigationController which is the UINavigationController that is an ancestor to this ViewController on the stack.
So if you had a RootViewController, called root, that at some point did this
FirstViewController * first = [[FirstViewController alloc] initWithNibName:#"FirstView" bundle:nil];
[self.navigationController pushViewController:first animated:YES];
[first release];
Then first.navigationController == root.navigationController
So inside of first calling
[self navigationController]
will give you the same navigationController that first was pushed onto in the first place.
One object needs a reference to the other. There are many ways to make this happen. For example:
Have the same object create both and, since it knows them both, tell them about each other
Create them in the same nib and hook them up with normal connections
Have the owner of the nib one of the objects is in know about the other
Essentially, this is just a matter of designing your application properly so that the objects can be told about each other. There is no one magic thing you do.