I am building an application that is constantly speaking to a webservice. So posting and getting data all the time. But all the data that I post and get should also be saved on the phone.
Problem 1
When I was looking through the examples. I saw that they are loading all the data in the appDelegate. For loading in small amount of data this is probably the best way to do it. But in my case, is it still the best way or should I do this on ViewController Level.
Problem 2
When I started the application I checked use core data this generated a lot of code for me in the appDelegate. But in this case I can't get to my managedObjectContext on viewController Level, right?
My question is now, what is the best way to get this properly done?
Kind regards
Problem 1
When I was looking through the examples. I saw that they are loading all the data in the appDelegate. For loading in small amount of data this is probably the best way to do it. But in my case, is it still the best way or should I do this on ViewController Level.
The use of an appDelegate for that is typical of sample code.
How to best deal with that depends strictly on your app. Encapsulating data transfer into your view controller is certainly a step forward compared to using the app delegate. But, depending on your app, you might also devise a more specific data load controller to encapsulate all the relevant behavior. Indeed, I think the latter option works best even for relatively simple projects.
Problem 2
When I started the application I checked use core data this generated a lot of code for me in the appDelegate. But in this case I can't get to my managedObjectContext on viewController Level, right?
If you look into the appDelegate.h file you should find properties for accessing core data from your controllers:
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
You could use that to access the managed object context through [UIApplication sharedApplication].delegate or you could factor that code out of the app delegate into your own model manager class. Again, this is strictly depending on your app. There are apps that use only 1 managed object contexts, apps that deal with more, etc. If your app does a very basic use of core data, you could leave this as it is.
Related
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.
I have a common application pattern: user enters data in the main view controller, then views it in a table in a modal view controller, where rows can be deleted or modified. I was following the general design strategy from the Stanford iPhone course, but somewhere things went off the rails and all I've been getting is SIGABRT's and exceptions like "Illegal attempt to establish a relationship 'xyz' between objects in different contexts."
As in the Stanford course, I use a singleton class called "Database" which should return the same context whenever requested. So the first commands in my viewDidLoad method on the main view controller are:
dbsingleton = [Database sharedInstance];
nmocontext = [dbsingleton managedObjectContext];
nmocontext is an ivar I use throughout the view controller. When the user wants to see the other view controller, with the table, I alloc-init it, then present it modally. (It has an NSFetchedResultsController that supplies the data from my store.) I've tried various strategies here:
I've made the NSFetchedResultsController a retained property set by the main view controller
I've made the NSManagedObjectContext a retained property set by the main view controller; and
I've used the singleton internally by repeating those two lines of code above at the beginning of the table view controller's viewDidLoad method.
Whichever I go with, the one problem I just can't solve is that after the user closes and deallocs the table view controller (and its NSFetchedResultsController), I start getting crashes in the main view controller when the store is accessed (like the "Illegal attempt" error mentioned above).
What are best practices for dealing with this common application pattern? I am still hoping to make this application iPhone SDK 3.x compatible, but I do seem to have fewer crashes when I'm using iOS 4 -- if there are underlying issues with 3.x that are causing me problems, please let me know and I may target iOS 4 only.
Thank you!
This is just a guess but I assume the following problem for your crashes after closing the tableview:
You declared a property
#property (retain, nonatomic) NSManagedObjectContext* nmocontext;
do you properly release the ivar nmocontext in dealloc?
If yes your problem is the assignment
nmocontext = [dbsingleton managedObjectContext];
This never retains nmocontext within your viewcontroller but you release it on dealloc.
Second:
"Illegal attempt to establish a relationship 'xyz' between objects in different contexts."
This is not a memory management issue, but you probably created another new context to add objects (like in the apple core data iphone samples) and tried to set a NSManagedObject as relationship from a different context.
It sounds like you don't have your singleton properly configured.
A singleton should override release to do nothing such that when it is sent a release message nothing happens. If you do not override release then any random piece of code anywhere in the app can kill the singleton and defeat the entire purpose of using a singleton. The next time you call singleton, you actually get another new object which in this case also returns a new managed object context.
See Cocoa Fundamentals Guide: Creating a Singleton Instance.
Singletons are powerful and flexible but very easy to do wrong. They are so easy to screw up that many experienced developers simply refuse to use them. If don't have experience with them, don't use them when you are just starting out.
I keep running into situations with UIViewControllers containing a large amount of IBOutlets connecting the controller to its view's subviews (typically UILabels).
Following "best practices", i.e. use retain on all UI elements: #property (retain, nonatomic) UILabel *theElement1, #property (retain, nonatomic) UILabel *theElement2, ... gives me insane amounts of boiler plate code in dealloc and viewDidUnload for the view controller.
The offending IBOutlets are never used nor set outside the UIViewController (the set-method is only used in viewDidUnload and when the nib is loaded) except automatically when the nib is loaded.
The result from "best practice" is:
dealloc littered with [theElement1 release], [theElement2 release] etc.
viewDidUnload with [self setTheElement1:nil], [self setTheElement2:nil] etc.
However, since all of those elements are known to be retained by the view anyway, and the view is released by the UIViewController at appropriate times, I see absolutely no reason whatsoever for me to manually manage this.
The reason for this particular "best practice" (as far as I can tell) is to be consistent with your retains. But once you start having a large amount of outlets, you're more likely to miss handling the some outlet somewhere in either of the two methods, than you'll have trouble correctly changing outlets to "retain" for those special outlets you really want to retain even after the view is goodbye.
Is there some reason for this "best practice" other than the one I know about or should I feel quite free to break this "rule" in the particular case of subviews to an UIViewController's view?
You should stick to this best practice. It protects you from very bizarre crashes when you access IBOutlets after a memory warning. Yes, you need to manually manage your IBOutlets. Accessorizer does a nice job of automating this code.
Before ObjC 2.0, we had to write all of our accessors by hand, too (#property and #synthesize are very new additions to the language). Things have gotten a lot nicer. As we move to the 64-bit ABI and garbage collection, things get even simpler (and you should expect these things eventually to make their way to iPhone).
But for now, follow the memory management rules as laid out in Memory Management of Nib Objects. You trade a really small amount of typing for a huge amount of debugging. (Hmm, looks like they've updated this doc again; time to study up myself.)
In regards to XCode templates with CoreData enabled, I've read unclear use of #property in window app using core data which goes over the 'what' in the templates. But I am having an issue with the 'why'. By declaring the category in the implementation file, the CoreData accessors act like private methods. The problem with that is whenever you want to use CoreData elsewhere in your app, you need some extra code.
I've figured you need to either supply your own method that exposes the managed object context, such as...
- (NSManagedObjectContext *)getManagedObjectContext
{
return self.managedObjectContext;
}
...which will allow other parts of your app to use it.
Or you would need to jam pack your app delegate with specific methods to return managed objects, ie getProducts or setUser.
Can anyone shed light on the reasoning here?
The reason for this is because you should be using dependency injection in your designs. This is the recommended design by the Core Data team. What is expected is that your app delegate will set the NSManagedObjectContext reference in your root view controller(s). From there the controllers will set or inject the necessary dependencies in the following view controllers.
This will lead to a more flexible design. I discussed it in depth in my article on the MDN (http://www.mac-developer-network.com/articles/cd0004.html).
If your project is big and needs to access the managed object context from outside of the AppDelegate,
I would just move the property declaration of managedObjectContext to the header file, as in:
#interface myAppDelegate : NSObject <UIApplicationDelegate> {
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
}
#property (retain,nonatomic) NSManagedObjectContext*managedObjectContext;
#end
Then the other parts of the app can just use appDelegate.managedObjectContext.
There's no reason to expose managedObjectModel or persistentStoreCoordinator outside the app delegate, though.
By the way I have a few comments about your usage of Objective-C:
Don't use get in front of the getter. For a property called foo, the getter should be
-(Foo*)foo;
and the setter should be
-(void)setFoo:(Foo*)_foo;
By convention, get... is used when a pointer is fed as a method argument, as in -[NSString getCharacters:range:] (See the Apple doc).
Follow the proverb, when in Rome, do as the Romans do.
I have been working on an iPhone project, where we created all the user interface programmatically in code. Now I'm going to start a new iPhone project and thinking of using Interface Builder instead, because it has been recommended to me as being a very useful tool, creating less headache than writing everything in code and in general much faster (regarding development time).
However, my team members have some concerns due to previous problems with using Interface Builder and resulting memory leaks. Therefor they suggest building everything in code again. I don't know where these concerns come from, but maybe someone with more experience than we have can give some insight on that topic.
Doing a simple Google search doesn't really provide any information proofing that there are any problems with memory leaks created by the Interface Builder itself.
By looking at the official documentation from Apple I only see these three things which I have to take care of:
#property (nonatomic, retain) IBOutlet UIUserInterfaceElementClass *anOutlet;
"You should then either synthesize the corresponding accessor methods, or implement them according to the declaration, and (in iPhone OS) release the corresponding variable in dealloc."
- (void)viewDidUnload {
self.anOutlet = nil;
[super viewDidUnload];
}
Anything I missed?
When you assign an IBOutlet via Interface Builder, that object is retained by the controller by default (even without explicitly setting a property with retain). Therefore, you need to either release all outlets, or set a property with assign.
This is a gotcha that gets most people, and leads to the most common of memory leaks. Especially on views that are repeatedly show and removed.