sharing an object between two viewcontrollers in objective c - objective-c

I am guessing that this maybe a silly beginner question, but I cant figure out the answer to it. I basically have two view controllers in my iphone app that I would like them to share a third class (.m and .h) that suppose to hold data that both suppose to use. Lets say for example that both views are displaying locations and presenting a table with some of this information manipulated - what i'd like to do is to have a third class, like an engine, that will do all that, and those views will just instantiate this engine and read the table/location data when needed.
My question is - how can I instantiate this engine in both my views but have in fact only one copy of the engine that both views read from. I know that when instantiating twice, two copies are being created, and i dont want that. i am hoping to make this engine "global".
is this possible at all in objective c? what would be the best way to go about that?
Thank you much all.

You might consider adding a #property to both view controller's that points to your model ("engine") object. When the view controller's are created, you can set that #property to point to the model. If the #property is retain, then it won't copy the model.

You have a lot of options when it comes to this. Following an MVC approach, you are on the right track in that you should have a single copy of this data (the model). How you get that to your view controllers is up to you. I'll give two ways and you can see which works better in your situation, but there more than ways to do this. Option 1) Create a singleton to house your model/data. You've probably seen this in the SDK when using stuff like ... = [SomeController sharedInstance]. The two view controllers can just use that shared instace. Option 2) You can instantiate the model somewhere at startup and pass it directly to the view controllers. Whether it's a singleton or not is not their concern. They just know they have access to some data. You can create a property like #property (nonatomic, retain) TheData *theData for each of the view controllers and pass it that way.

Since you only have one of these "Engines", I'd suggest going the singleton route.
Create a static method that returns an instance to the object you want shared, then you can use that method in each class.
forgive my syntax... I don't have my objective C stuff in front of me atm, but essentially you'll want to do something like the following.
EngineClass.h file:
STATIC EngineClass * getSingleton();
STATIC EngineClass * INSTANCE;
EngineClass.m file:
STATIC EngineClass * getSingleton()
{
if(INSTANCE == null)
{
INSTANCE = new EngineClass();
}
return INSTANCE;
}

Related

How to maintain the value of a variable after switching view controllers? [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 8 years ago.
I need to access the value of a variable in ClassA.m after I load the view ClassB.m, but it seems as though when I switch the view from ClassA to ClassB, the variables from class A are destroyed. What is the best way to maintain this variable in ClassA? In Java, this would be rather easy, in the form of a static variable. However, I am not aware of such a concept in Objective-C. If you would recommend using an "extern" variable, I tried that, and that variable type also seemed to be destroyed after the view switch? Perhaps I am implementing incorrectly, but what are your thoughts? How do I maintain the value of a variable in the second view after the first view is dismissed?
You can create property in new viewcontroller and pass current viewcontroller's variable to new. see exp.
DetailsViewController *detailsviewcontroller = [[DetailsViewController alloc] initWithNibName:#"EventDetailsViewController" bundle:nil];
eventdetailsviewcontroller.event = localvar;
[self.navigationController pushViewController:detailsviewcontroller animated:YES];
Forget about static variables for now. The idea is that you want an object to keep reference of those variables regardless of which view is on. That's what the mediator pattern is for. Basically you want to have a controller of controllers (make it a singelton), and that controller can keep a reference to all the variables you want to keep around while views come and go.
This way you decouple your code, which translates to decreasing the dependency between potentially unrelated controllers and reducing glue code.
I gave a similar answer here as well.
You can use static variable in Objective-C. This is an example in Test.m file
static NSMutableDictionary* single = nil;
#implementation Test
#end

NSUserDefaults IOS Accessible Everywhere?

I am wondering if the NSUserDefaults object is shared and can be accessed from within the app delegate as well as within several of my view controllers. Basically I need to pass data from the app delegate back and forth to the view controllers. I don't want to use a singleton. I was wondering if the NSUserDefauflts object was a way to do this.
If this is possible, how would I initialize the object so that is possible?
Thanks!
If you just use [NSUserDefaults standardUserDefaults], the same instance will be returned every time. Different classes can then use it to store data that is persistent across sessions.
If you're just trying to pass data between parts of the app, but not store it, user defaults are not the appropriate way to do so. You should expose methods or properties on your classes that take as input the data you need to pass.
Well, it is but that's not really what it's designed for. The normal design pattern is to pass the objects back and forth between your view controllers "manually." You want your view controllers to be as independent -- reusable -- from the rest of your application as possible. Tying them to NSUserDefaults isn't a good way to do that!
You should not be doing any processing in your app delegate. Ideally, you should initialise your window, root view controller (if not doing it by storyboard) and model and that's it. All processing should be done elsewhere (mostly in view controllers talking to the model classes).
Make your root model class a singleton so that all your view controllers can talk to it via an interface of your choosing.
Making a singleton is not hard:
#interface MyModel: NSObject
+ (MyModel *)sharedModel;
#end
and the implementation:
#implementation MyModel
+ (MyModel *)sharedModel
{
static MyModel* modelSingleton = nil;
static dispatch_once_t once;
dispatch_once(&once, ^{
modelSingleton = [[MyModel alloc] init];
});
return modelSingleton;
}
#end
And then you just use:
[MyModel sharedModel]
to access it.

What are NSManagedObjectContext best practices?

I'm working with a Navigation Controller based iOS app. There are multiple tableView screens that pull and save data from a Core Data persistent store. Most of the data for the different table views comes from NSFetchedResultsController instances or NSFetchRequests.
The app works as intended but I have been getting a few random crashes and glitches that seem to be related to Core Data. For example sometimes when I save the context the app will crash but not always. Another thing I've been seeing is the very first tableView doesn't always update the reflect the data that was modified in it's detail view.
Currently I'm passing around a single Managed Object Context that was created in the app delegate to each of the different view controllers by setting the context property of the view controller just before I push it onto the navigation stack.
This seems like a clunky, hacky way of getting the job done. Is there a better design pattern to use?
I noticed in one of the WWDC sessions using delegation but I've never used creating my own delegates before and haven't been able to puzzle it out of the WWDC session.
Thanks.
=)
Use singleton NSManagedObjectContext for all Controllers isn't a best practice.
Each Controller should have your own Context to manage specific, sometimes atomic, operations at document store.
Think if you can edit a NSManagedObject attached to Controller that pass the same Context to other Controller that will select another instance to delete or edit.. you can lost the controll about modified states.
When you create a view controller, you pass it a context. You pass an
existing context, or (in a situation where you want the new controller
to manage a discrete set of edits) a new context that you create for
it. It’s typically the responsibility of the application delegate to
create a context to pass to the first view controller that’s
displayed.
http://developer.apple.com/library/ios/#documentation/DataManagement/Conceptual/CoreDataSnippets/Articles/stack.html
1)
Use a singleton for your CoreData setup (NSPesistentStoreCoordinator, NSManagedObjectModel & NSManagedObjectContext). You can use this singleton to execute the fetch requests you created in your Models and to add or delete Entities to your Context.
2)
Delegates are not that hard. Following is a sample:
#class SomeClass
#protocol SomeClassDelegate <NSObject> //Implements the NSObject protocol
- (void) someClassInstance:(SomeClass *)obj givesAStringObject:(NSString *)theString;
- (BOOL) someClassInstanceWantsToKnowABooleanValue:(SomeClass *)obj //Call to delegate to get a boolean value
#optional
- (NSString *) thisMethodIsOptional;
#end
#interface SomeClass : NSObject {
id<SomeClassDelegate> delegate;
//Other instance variables omitted.
}
#property (assign) id<SomeClassDelegate> delegate;
#end
#implementation SomeClass
#synthesize delegate;
- (void) someMethodThatShouldNotifyTheDelegate {
NSString *hello = #"Hello";
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(someClassInstance:givesAStringObject:)]) {
[self.delegate someClassInstance:self givesAStringObject:hello];
}
}
#end
Option 1 could be something like this, you will have to setup the variables in the init of the object (and implement the singleton ofcourse):
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface CoreDataUtility : NSObject {
#private
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
}
+ (CoreDataUtility *)sharedCoreDataUtility;
- (NSEntityDescription *) entityDesctiptionForName:(NSString *)name;
- (NSMutableArray *) executeRequest:(NSFetchRequest *)request;
- (id) getInsertedObjectForEntity:(NSString *)entity;
- (void) deleteAllObjects:(NSString *) entityName;
- (void) deleteManagedObject:(NSManagedObject *)object;
- (void) saveContext;
#end
Currently I'm passing around a single Managed Object Context that was
created in the app delegate to each of the different view
controllers...This seems like a clunky, hacky way of getting the job
done. Is there a better design pattern to use?
There's nothing particularly special about a managed object context in this respect, it's just another object that your view controller may need to do its job. Whenever you're setting up an object to perform a task, there are at least three strategies that you can use:
Give the object everything it needs to get the job done.
Give the object a helper that it can use to make decisions or get additional information.
Build enough knowledge about other parts of the application into the object that it can go get the information it needs.
What you're doing right now sounds like the first strategy, and I'd argue that it's often the best because it makes your view controllers more flexible, less dependant on other parts of the app. By providing the MOC to your view controllers, you leave open the possibility that you might someday use that same view controller with a different context.
Jayallengator makes the helpful observation that every managed object has a reference to its context, and if you're passing around specific managed objects you don't also need to pass along the context. I'd take that a step further: if you're passing specific managed objects to your view controller, the view controller often won't need to know about the context at all. For example, you might keep Game objects in your data store, but a GameBoardViewController will probably only care about the one Game that's being played, and can use that object's interface to get any related objects (Player, Level, etc.). Perhaps these observations can help you streamline your code.
The second strategy is delegation. You'll usually use a protocol when you use delegation, so that your object knows what messages it can send its helper without knowing anything else about the helper. Delegation is a way to introduce a necessary dependency into your code in a limited, well-defined way. For example, UITableView knows that it can send any of the messages defined in the UITableViewDelegate protocol to its delegate, but it doesn't need to know anything else about the delegate. The delegate could be a view controller, or it could be some other kind of object; the table doesn't care. The table's delegate and data source are often the same object, but they don't have to be; again, the table doesn't care.
The third strategy is to use global variables or shared objects (which is what people usually mean when they talk about singletons). Having a shared object that you can access from anywhere in your code is certainly easy, and you don't have that "klunky" extra line of code that configures your object, but it generally means that you're locking your view controllers in to using that shared object and no other. It's a lot like gluing a hammer to your hand because you know for certain that that hammer is the tool you need. Works great for pounding nails, but it can be painful if you later discover that you'd like to use the same hand for driving screws or eating dinner.
The singleton approach seems to be best-practice, but another trick I found useful was that in cases where you're passing a NSManagedObject from one view controller to the next anyway (usually as an instance variable), you don't need to also pass the NSManagedObjectContext since you can get the context from the object you passed in by invoking [myManagedObject managedObjectContext]. This can be a handy shortcut when there's maybe only one or two methods where you need the context and you don't want the overhead of creating yet another NSManagedObjectContext ivar/property.

split iphone objective-c code in to multiple files

I have written a few apps for the iphone now, but they are all written in what I consider to be a lazy, unstructured way.
I have started a new project and have created several Objective-C classes (subclass of NSObject). the problem I have is getting the logic correct in my head. My structure is as follows
viewController.h
viewController.m
plotPoints.h
plotPoints.m
handleFeeds.h
handleFeeds.m
So the main file is the view controller and I include in it's header file the other classes. My problem is that in the other class files, eg plotPoints.m - if I try to refer to a variable I set in the view controller, it says it's not set. I have included the viewcontroller in the plotPoints.h file - but still it doesnt work.
what is best practice for separating code in this way? In this example, I have webservice feeds which I want to handle in one class, then process those results in another and handle the main UI in the view controller.
Thanks for any information.
I say the Controller shouldn't be referenced by your - as I understand - external classes (plotPoints and handleFeeds, by the way these should definitely begin with an uppercase character).
Actually, it should be the exact opposite, your viewController should be using methods and properties of your external classes. PlotPointsand HandleFeeds should not have to refer to instance variables of your Controller, let it pass them as arguments for you methods instead.

Objective C protocol as an equal to Java Interface?

The question is not only regarding the headline, but more of a "how will I achieve this, without trying to force a Java/Flash design into an Objective C (iPhone)program".
I have 6 views that extends UIView, these views all have different behavior but share certain methods, like -(void) update and -(void) changeState:(NSInteger)state.
A viewController, whose job is it to update, instantiate and display these views has a switch block to do this. So switch(4) {...} instantiates UIView4, but as I need a reference to the currently instantiated view (to do update and changeState:), I have a UIView property on my ViewController called self.currentView. As the instantiated UIView4 extends UIView I can easily go [self.currentView addSubview:UIView4instance] and then release the UIView4instance.
Now how will I call the [UIView4instance update] method on the view? or the [UIView5instance changeState] etc. etc.
Since I added it to self.currentView which is of type UIView it no longer has any reason to believe it has an update or changeState: method, meaning I cannot iterate the views and send them these messages.
This approach brings on a ton of other problems, I would need to test and typeCast my views each time I needed to do any operations on them.
If I were doing something like this Composite Pattern approach in, say, Java. I would either write an interface that all the views (UIView1, UIview2.... UIViewN) would implement. Or maybe an abstract class that all the views inherited the changeState: and update methods from.
This way I could have self.currentView just know that I'm adding objects to your view and they all conform to these methods.
The two solutions I can think of, with my very small Objective-C experience is:
doing it with delegation or categories, but this seems overkill in every way :/
I guess I could also extend UIView and then extend my class extending UIView again, but there is probably a reason Objective-C does not directly support abstract classes...
Hope someone could point me in the right direction regarding these issues.
Thanks:)
Yes it is equal. You can declare a protocol
#protocol MyViewProtocol
-(void)update;
-(void)changeState:(NSInteger)state;
#end
and declare your subclasses like
#interface MyUIView3 : UIView<MyViewProtocol> {
....
}
....
#end
Then, the declaration
UIView<MyViewProtocol>* view=[[MyUIView3 alloc] init];
means that view is an instance (of a subclass of) UIView which also conforms to MyViewProtocol.
Just the way it works in Java, I think. See the apple doc on protocols.
One thing to be aware of is that while defining a protocol like this is a convenience and certainly makes things clearer, it is by no means necessary to make your solution work. Objective-C binds methods at runtime, and so all you really need to do is to make sure all your view classes implement the methods you care about and call them.
You will get a complier warning for this, but it will work.
Now, in general it's probably preferable to define a protocol like this and it's what I generally do. But it's also important to remember that runtime binding is there and can be incredibly powerful.