iPhone MVC app: Where should I put the model? - iphone

I'm pretty new to iPhone development.
I am building an app which has multiple views and controllers. There is only one model.
I need to share the model amongst all of the controllers; so I have instantiated the model inside the App Delegate header file:
#interface MyAppDelegate
(...snip...)
#property (nonatomic, retain) CalcModel *model;
and then synthesized it accordingly.
Inside a controller, I have tried to reference the model like so:
CalcModel* model = [[[UIApplication sharedApplication] delegate] model];
The problem is that the compiler says '-model' not found in protocol
This is probably because the delegate field returns the protocol type, not the concrete MyAppDelegate type... so should I cast [[UIApplication sharedApplication] delegate] to MyAppDelegate, so I can access the model property? If so, how?
Or is this all wrong? More broadly, how would you share a model amongst view controllers?
many thanks for your help

Yes, just cast it. I #define a macro that wraps this into a simple call to make it easier.
With regard to one way to implement the model structure, there are some useful pointers in this article:
http://www.bit-101.com/blog/?p=1969
(We just implement models as singletons themselves, and use KVO from the views to listen for changes to properties.)

You can typecast it just like you typecast any other object
CalcModel* model = (MyAppDelegate *)[[[UIApplication sharedApplication] delegate] model];
you'll have to instanciate the model in you appdelegate .m

Related

How do I get data from Core Data from another class?

I have created a project where Core Data is included. If I were to retrieve data from another class other than my AppDelegate - where all the needed methods are - how would I do that ? So how do I get the context and the NSManagedObjectModel ? Do I need those, or is there another way round ?
I have tried making a new NSObjectContext object in my new class but then the debugger says it needs the NSManagedObjectModel. I am a newbie and I'd appreciate any help.
Yes, you need the NSManagedObjectContext. Basically what you have to do is inject the managedobjectmodel in the class where you want to query the database.
So in the class where you want to query the database create a property like this:
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
And then do in your app delegate:
myViewController.managedObjectContext = self.managedObjectContex;
If this view controller does not have a reference within the app delegate then you can do this:
MyAppDelegate appDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate
myViewController.managedObjectContext = appDelegate.managedObjectContex;
Hope that helps.

How do you pass an object between ViewControllers on iOS?

Using the "Tab Bar" template in Xcode 4, each ViewController is created automatically, so I don't have the chance to set any properties on a ViewController as it's created. I want each ViewController to have access to an object (an instance of FMDB's FMDatabase).
There are a number of questions on StackOverflow relating to this already, but some are assuming that you are creating the VC's by hand, and others recommend using the AppDelegate as a mediator:
MyAppDelegateClass *appDelegate = [[UIApplication sharedApplicaton] delegate];
myLocalProperty = appDelegate.someDataModelProperty;
The above seems rather "hacky" to me. Is there a better way to access a single object from multiple ViewControllers?
Most probable implementation of FMDB's Data base would be to implement it as a Singleton and access it through out the application. Is there any reason for not doing so ?
This link should help you in doing so:
How do I make FMDB's database a singleton
To expand on KKK4SO's answer, you could implement the Database as a singleton. Then, have all of your UIViewControllers be a subclassed UIViewController that contains methods to access and modify the Database singleton.
MyAppDelegateClass *appDelegate = [[UIApplication sharedApplicaton] delegate];
myLocalProperty = appDelegate.someDataModelProperty;
There is a spelling error in this code 'sharedApplicaton' is incorrectly spelled it should be 'sharedApplication'.
Shame on me for copy and pasting! Anyway this will work for a quick and dirty way of passing data between ViewControllers etc.

Iphone access a property value from AppDelegate

How to access a property value of AppDelegate class from someView Controller without creating reference of the delegate in view controller?
I'm not quite sure what you mean - there are multiple ways to get information from your application delegate into a view controller, and the phrase "without creating reference of the delegate" is unclear. Your options basically are:
Reference the application delegate, casting as appropriate. You would write code in your view controller class like: id propertyValue = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] myProperty];
Pass the property in when creating the view controller. This requires the view controller to have a #property declared and #synthesized for use, then you would have the app delegate just set the property on the view controller instance.
Neither of these options require that you retain a copy of your app's delegate as a #property, but the first does reference the delegate once.
[UIApplication sharedApplication].delegate
You'll also need to include the app delegate header file in your view controller and possibly typecast the delegate from id to your actual app delegate class.
#include "MyAppDelegate.h"
((MyAppDelegate *)[UIApplication sharedApplication].delegate).myProperty;
[UIApplication sharedApplication].delegate;

Want to create a container class which will only exist once

I want to make a class that can hold settings for my app. Its pretty basic. I will access it from a few different classes, but only want 1 version of this container class to exist so they all see the same data.
Is there something special i need to flag for this?
Here is what I've done so far:
Filters.h
#import <Foundation/Foundation.h>
#interface Filters : NSObject
{
NSString *fuelType;
}
#property (nonatomic, copy) NSString *fuelType;
#end
Filters.m
#import "Filters.h"
#implementation Filters
#synthesize fuelType;
#end
Is there some flag i need to use when i alloc an instance of this class or how should I work this if I need to access the fuelType value from 2 different classes?
Thanks
-Code
For global application settings a better way would be to use NSUserDefaults or if you want to store data for use you should look up using core data and sqlite.
Lastly, if you want to go for ease of use you could do a core data style app delegate class and grab it by using:
[[[UIApplication sharedApplication] delegate] myClass] that way you'll always have that version of the class.
You need a singleton:
you can create your singleton by your own or use AppDelegate object which is an object that is always alive and never released while your application in the frontground (just put the vars needed there and initialize them dynamically).
Here are some links on how to create a singleton.
Cocoa fundamental Guide: Creating a Singleton
and
CocoaDev Singleton Pattern
What you're looking for is a singleton. Most people advise against using singletons though as it is often considered "dirty". See "Singleton" in this apple doc to learn more about it.

Refer to an integer from one ViewController from another

I'm unable to refer to my integer pickedItem declared in my RootViewController.h in my DetailViewController.m file.
Not sure if I should declare this as a global variable, but tried unsuccessfully to do so.
I think this should be simple, but I haven't got any other suggestions (from other posted answers) to work.
Thanks in advance.
You can access the app delegate through [[UIApplication sharedApplication] delegate] this call. And then can access the root view controller's property (assuming you have access to the rootViewController object in appDelagate).
In RootViewController.h
#property(nonatomic, assign) NSInteger myInt
And from anywhere in the code
UIApplicationDelegate *delegate = [[UIApplication sharedApplication] delegate];
delegate.viewController.myInt = 31;
p.s. I have just typed the code, not compiled. So there might be some typo.
You just wouldn't want it coded this way. I recommend taking a look at NSNotificationCenter, or create a delegate class for yourself, to communicate to the DetailViewController of page changes. There shouldn't be a dependency from detail -> root the way you have it.
Based on your code above, I don't see where you're setting rootViewController on detailViewController? Is it nil? I'd think referencing rootViewController.pickedItem if rootViewController was nil would cause a crash, but worth checking.
Also, is pickedItem being set appropriately? In other words, is it set before the detail code is being called?