PDA

View Full Version : passing Data from AppDelegate to UITabBarController




rubyruby
Apr 28, 2009, 03:03 AM
Hi,

how do I pass a data model (which I've created on my own) to the UITabBarController (which is my root view) in my AppDelegate?

The problem is, that UITabBarController (e.g. addController) doesn't include
my model (e.g. addController.model). So I would have to subclass it. Is this a proper solution?

Regards,

rubyruby



robbieduncan
Apr 28, 2009, 04:01 AM
Do it the other way round. Any instance can get a pointer to the app delegate so simply provide an accessor method for the data model there.

Or make the "root" of your data model a singleton object and access it that way.

rubyruby
Apr 28, 2009, 05:23 AM
Thanks, the way you've described it, is my current solution. But I've read, that it would be better design to have a model, which "wanders" around the views instead of a central one.

Anyway, the central approach of getting a instance of AppDelegate works. I'll stick with it, until I see some better solutions. ;)

Luke Redpath
Apr 28, 2009, 07:44 AM
Do it the other way round. Any instance can get a pointer to the app delegate so simply provide an accessor method for the data model there.

Or make the "root" of your data model a singleton object and access it that way.

Mmm, whilst sometimes necessary, making everything singletons or accessing the app delegate all over the place seems like a code smell to me.

If you need to pass data into your controller from your app delegate, just add an accessor (or a property) to your own subclass of UITableViewController, e.g.:


// MyController.h

@class MyModel;

@interface MyController : UITableViewController {
MyModel *model;
}
@property (nonatomic, retain) MyModel *model;
@end

// MyController.m

#import "MyModel.h"

@implementation MyController
@synthesize model;
@end

// YourAppDelegate.m

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
Model *someModelInstance = [[MyModel alloc] init];
MyController *controller = [[MyController alloc] initWithStyle:UITableViewStylePlain];
controller.model = someModelInstance;
[someModelInstance release];
[window addSubview:controller.view];
[controller release];
[window makeKeyAndVisible];
}


Of course, I'm making assumptions about where your instance of your model comes from and where the controler is initialized (it might be loaded from a nib into an instance variable/property of your app delegate).

robbieduncan
Apr 28, 2009, 08:00 AM
Mmm, whilst sometimes necessary, making everything singletons or accessing the app delegate all over the place seems like a code smell to me.

I think it depends, very much, on the exact data model. If there is a single data model and only ever will be then I'd make it a singleton. If you are asking the controller to display a specific piece of data that will be different every time then I'd pass it that data to display.

The OP did not really give us enough data to work out which case he was in, so I simply suggested the easiest solution from where it sounded like he was.

rubyruby
Apr 28, 2009, 11:35 AM
Hey guys,

that's right. I didn't give you much information. I have a handful of models. Anyway, you two worked out nice solutions:

1. If there's a single model: singelton
2. If there are many models: subclassing

Cool.. Thanks Robbie and Luke

Luke Redpath
Apr 28, 2009, 12:51 PM
I'd still favour the latter solution as it is more flexible in the long run; if having your model object as a singleton is no longer appropriate, you'll have to change more code. I've always considered singletons a code smell and I try and avoid them unless absolutely necessary.

samsonsu
May 30, 2009, 03:53 AM
Mmm, whilst sometimes necessary, making everything singletons or accessing the app delegate all over the place seems like a code smell to me.

If you need to pass data into your controller from your app delegate, just add an accessor (or a property) to your own subclass of UITableViewController, e.g.:


// MyController.h

@class MyModel;

@interface MyController : UITableViewController {
MyModel *model;
}
@property (nonatomic, retain) MyModel *model;
@end

// MyController.m

#import "MyModel.h"

@implementation MyController
@synthesize model;
@end

// YourAppDelegate.m

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
Model *someModelInstance = [[MyModel alloc] init];
MyController *controller = [[MyController alloc] initWithStyle:UITableViewStylePlain];
controller.model = someModelInstance;
[someModelInstance release];
[window addSubview:controller.view];
[controller release];
[window makeKeyAndVisible];
}


Of course, I'm making assumptions about where your instance of your model comes from and where the controler is initialized (it might be loaded from a nib into an instance variable/property of your app delegate).

Saving & initializing model in view controller could be a problem if you have multiple views in your app. Upon low memory warning, view controller might re-init (if it's not the current view controller), and that causes your data model to re-create and you lose all the state.

This can be easily proven with simulator. Add a button in your app to make some change to your data model (as a member of table view controller). Switch to a different view (so table view controller will be pushed into stack). Now send a simulated low memory warning, then come back to your table view controller. Inspect the model data -- you'll find your change is gone. Model is now back to initialized state.

If you set a breakpoint in your data model's init function and repeat the above, you'll find the data model is re-init'ed when you switch back after low-mem warning.

I learnt it the hard way.

Now I store data model as a property in delegate. Everything works very well now. I believe Singleton works well too.

firewood
May 30, 2009, 02:51 PM
Mmm, whilst sometimes necessary, making everything singletons or accessing the app delegate all over the place seems like a code smell to me.

And for a small app with a countably small number of objects and models, wasting a users memory and battery life by using layers of properties, subclasses, and notification handlers seems like an even smellier waste of resources to me.

Just stick a pointer to the model in a global. Or if the apps total state data is small enough, just put them all in global variables. One less level of indirection to potentially trash your CPU cache.

Not every class needs to be designed to scale to 1000's of instances collaborating remotely. Remember that all this dynamic OOP stuff, while good for the developer, can be bad for the users battery life. Spend some time thinking about them.

imho

Luke Redpath
May 31, 2009, 08:14 AM
Saving & initializing model in view controller could be a problem if you have multiple views in your app. Upon low memory warning, view controller might re-init (if it's not the current view controller), and that causes your data model to re-create and you lose all the state.
.

This is completely wrong.

The default behaviour of UIViewController when handling low memory warnings is to release and reinitialize it's sub-views. The entire object isn't released and re-initialized. Your properties will be safe.

Obviously if you re-initialize the controller yourself you'll need to pass the same model object back into it.

Or you could just make sure your model object is saved when the view changes.

Luke Redpath
May 31, 2009, 08:15 AM
And for a small app with a countably small number of objects and models, wasting a users memory and battery life by using layers of properties, subclasses, and notification handlers seems like an even smellier waste of resources to me.

Just stick a pointer to the model in a global. Or if the apps total state data is small enough, just put them all in global variables. One less level of indirection to potentially trash your CPU cache.

Not every class needs to be designed to scale to 1000's of instances collaborating remotely. Remember that all this dynamic OOP stuff, while good for the developer, can be bad for the users battery life. Spend some time thinking about them.

imho

I'm not a big fan of premature optimisation. Good design first, optimise later. Good design isn't necessarily about scaling, its also about making things easier to test and refactor. Sure, for a small toy app you can probably get away with stuffing everything in your app delegate but for anything else I'd stop using the app delegate for what it isn't intended.

I don't buy the argument that having a few more classes and objects (i.e. a less coupled design) will make that much impact on the user's battery life. Got any comprehensive figures to back that up?