How to properly pass NSArray / NSMutableArray from one UIViewController to another - iphone

An iphone app I'm working on is terminating periodically ... and I have a feeling it is because of how I'm accessing a shared NSArray amongst several view controllers. So ...
What is the best way to pass NSArray/NSMutableArray amongst several ViewControllers ... all of which can modify and/or set it to nil or whatever?
Thanks

There are two approaches, generally speaking.
In the first approach, when you instantiate your next view controller, you could set an array property to "inherit" from the current (soon-to-be previous or parent) view controller:
MyNextViewController *_myNextViewController = [[MyNextViewController alloc] initWithNibName:#"MyNextViewController" bundle:nil];
_myNextViewController.myViewControllerArray = self.myViewControllerArray;
...
In the second approach, you could create a myAppDelegateArray property in your application delegate, instantiating the array when the application initializes (or instantiated somewhere else, on demand).
You can then call the getter for this property from any class — including view controllers.
For example, within an instance of MyNextViewController, you might have a property called myViewControllerArray and you would set it as follows:
self.myViewControllerArray = [UIAppDelegate myAppDelegateArray];
You would add a #define statement somewhere in your application constants file, e.g.:
#define UIAppDelegate ((MyAppDelegate *)[UIApplication sharedApplication].delegate)
or use the full [UIApplication sharedApplication].delegate call, if you prefer.
As a general approach, people seem to prefer the app delegate approach, as it decentralizes access to the desired property.
With this approach, if you rearrange your view controllers or insert new view controllers into your VC hierarchy, you wouldn't need to debug child view controller properties inherited from parent view controllers, because a reference is always available from the app delegate.

you are probably not retaining it, it gets deallocated and you are trying to access it again. try to send a [myArray retain] where you are using it (in each of the controllers), and [myArray release] when you are done with it

Related

How to make a delegate object accessible throughout a ViewController

I'm trying to get an instance of my AppDelegate accessible to all methods in each ViewController that I have. If I try to declare it with other class variables I get Initializer Element is not a compile-time constant. If I declare it in a method within the ViewController however I am able to use it. I am trying to save integers and floats to properties I have set up in the AppDelegate (a big no-no I know, but this is a project for an introductory class and I'm not expected to get too advanced, especially since everything we've done so far is not compliant with the MVC paradigm). The app uses a toolbar to switch between views using the app's ViewController to load the other ViewControllers as subviews. I was going to put the AppDelegate declaration and update statements in the ViewDidUnload method of each view controller, but I'm not sure that the Views are unloaded whenever they are switched (they're switched by removing the current View from the SuperView and loading the new one as a Subview at index 0). What happens to the views that are not currently being viewed then? Is there a method that detects that that I could implement the AppDelegate declaration and updates into?
I guess ideally I'd like to be able to access the AppDelegate object in any method in my ViewControllers because I have a lot of quantities being updated throughout and would like to have those quantities updated in the AppDelegates values as soon as they happen, since I'm not sure what happens with a View is cleared from SuperView
Thanks in advance everyone
You can access your app delegate via [[UIApplication sharedApplication] delegate] from anywhere in your application.
You should never instantiate another copy of the object on your own. The system does this for you at startup.
As for detecting changes, you can override the viewDidDisappear method of UIViewController. (You're correct--in general, they will not be unloaded when switched, and viewDidUnload will not be called)

passing data back to a previously allocated UIViewController

I have a view controller that then has a button that passes to an option menu.
When options are set they need to be past back to the previously allocated viewcontroller.
How is this possible without 'alloc and init another' instance of the object?
You can achieve this by using a delegate protocol. First view controller should become the delegate of the second view controller and then you can call this delegate method in your first view controller once the selection is done.
You can lookup google for implementation of delegates in objective-c. Its pretty simple. Add a
#protocol <delegatename>
<declare delegate method>
#end
Create a member variable in the second view controller for assigning the delegate. And define the method in the class implementing the delegate.
When you init your option viewController, pass it a reference to its parent.
I.E.
[[OptionViewController alloc] initWith...: parent:];
Use a #property or a method or somesuch to call on the parent to pass the data back.
You could use a shared singleton?
http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html
Or save the parameters to nsuserdefaults and read them back in in your first viewcontroller
or some other temporary store such as your appdelegate
I've used all three of the above approaches before.

Accessing a view controller's function/variable from other view controllers

I'm currently making the initial menu view controller, which sets up the setting for main game view controller..
so in my menu game controller, I have
#import "MainGameViewController.h"
#implementation menuViewcontroller
......
-(void)setting{
NSMutableDictionary *regions =
[(MainGaimViewController *)self.delegate regions];
NSNumber *yesBool = [NSNumber numberWithBool:YES];
NSNumber *noBool = [NSNumber numberWithBool:NO];
[regions setValue:yesBool forKey:#"KM"];
[regions setValue:noBool forKey:#"KF"];
}
but this gives me the "Request for member 'delegate' in something not a structure or union
regions is a NSMutableDictionary in main game view controller.
so I think menuViewController is not being able to access the function/variable in main game view controller despite the import.
currently, I haven't declared "class MainGameViewController" in my menu implementation file. Could that be why? should I make an object of maingameviewcontroller and use it?
What could be wrong?
Please help me out..
I find it is much cleaner and clearer to put application-global data in separate singleton classes rather than wedge them in to the application delegate object and to try passing around pointers to root-level view controllers. View Controllers should focus just on the job of managing its view and responding to actions, and interacting with data models through the view. The data models themselves and app global data generally should sit outside of ViewControllers. The singleton pattern works nicely for data management, as the data is easily available to any piece of code in the app that needs it without having to worry about setting up delegate protocols, or whether a view controller owning data is valid any more.
You can see my answer to this question for how to set up a singleton data manager class:
Objective C: store variables accessible in all views

How to access one UIViewControllers properties from another UIViewController?

I have one single MainViewController which has of course it's one main UIView. I have this main view comprised of many different subviews.
Some of these subviews have their very own ViewController.
Lets say the MAIN view (whose delegate is primarily MainViewController) has a container which loads another UIView that uses a separate UIViewController- SecondaryViewController as the delegate for most it's actions.
This container view is of course loaded in MainViewController via
MyContainerViewController *myContainerController =
[[MyContainerViewController alloc] ...];
[self addSubView: myContainerController.view];
the controller for myContainerController.view though is MyContainerViewController. How inside this controller do I access MainViewController properties? Specifically I need to access MainViewController's - self.navigationController property to push a new ViewController? :)
Does this make any sense? I assume there's going to be casting of some sort involved since it seems I need to somehow retain a reference to MainViewController inside SecondaryViewController?
It doesn't make sense to push a new ViewController from the SecondaryViewController in the MainViewController.
This screws up the design of the code. A child object will access its parents method to call a method. By other words: bad code.
Make a delegate call from the SecondaryViewController to the MainViewController that it state has changed. Then the MainViewController can decide to do with the call and the SecondaryViewController will not know anything about the implementation of the MainViewController.
So:
Make a protocol in SecondaryViewController.
Let the MainViewController be SecondaryViewController's delegate.
Implement the delegate method in MainViewController which pushes the new ViewController.
Expose the desired sub-view controllers as properties of the view controller that contains them.
Expose your root view controller(s) as properties of your app delegate, and synthesize them also.
When you want to access a different UIViewController, first obtain a reference to your appDelegate:
MyAppDelegate* myAppDelegate = [[UIApplication sharedApplication] delegate];
Then just use your chain of properties to get access to your desired view controller.
SubSubViewController* ssvc = myAppDelegate.rootViewController.subViewController.subSubViewController;
Some folks frown upon the use of the sharedApplication class method to obtain the reference to a delegate, but I've used it in multiple apps and not suffered for it (yet). The alternative is to pipe your appDelegate through your hierarchy of viewControllers.

How do I access the managedObjectContext from a controller deep in the UI?

I'm still a little fuzzy on understanding iPhone/Cocoa in general so this is probably a simple question.
I have a CoreData Window-Based App for the iPhone. The rootController is a UITabBarController. The first tab view has a UINavigationController attached to it with a table in it's main view.
When the App starts the objectContext is set up, which makes sense to have the App do that once. But now I have the managedObjectContext in the main Controller but I want to get that passed down to the Controller of the View inside the navcontroller, inside the first item in the TabBarController's tab list. How do I do this?
Would naming the one of the fields in the UI Inspector Tool allow me to do something like:
tabcontroller.navcontroller.manageObjectContext = self.managedObjectContext;
Would this only work if the controller was instantiated and 'live'. (Do the controllers not get instantiated until they are needed?) What if this was in a view that was for the most part hidden?
Anyway this is probably a simple thing I'm just not understanding things properly yet.
What is the general right way to share the manageObjectContext that is created and setup in the rootController to the many sub-controllers in the app?
I'm guessing this is the preferred method assuming the core-data initialization is done in the AppDelegate:
[[[UIApplication sharedApplication] delegate] managedObjectContext]
I usually give controllers a - (id)initWithManagedObjectContext:(NSManagedObjectContext *)context init method and a corresponding variable.
If a controller creates another controller in turn, it will, if needed, pass the NSManagedObjectContext to that controller in the same manner.
If you don't want to create an extra init method, just give the controllers a property for the NSManagedObjectContext and set that property directly after creating them.
I usually try to limit the number of controllers that directly deal with and "know about" Core Data though.
The answers to this question provide several means of accessing the Core Data stack deep within your application. As I indicate in one of the comments, I prefer to use a singleton DatabaseController that can be accessed from wherever, similar to how the NSUserDefaults' standardUserDefaults works.