Singleton CoreData manager available to all UINavigationControllers embedded views - ios

I'm wondering if the way my CoreData manager interacts with my views is the correct/best/most efficient way possible.
I use a standard singleton pattern, the Apple example, to house my CoreData stack. It also contains utilities for use with a web service and other helper methods.
There's a UINavigation controller with 2 viewControllers, a tableViewController and another viewController programmatically created viewController.
The first two viewControllers are a setup (web service address etc) and login respectively. Right off the bat I pop to the login view (second view). On a successful login, the tableView is pushed. On the selection of a cell, a view is created programmatically and pushed.
Each of these views have a need for the data store, so in their viewDidLoad, I'm grabbing the singleton.
Is this the way to do things? What are other ideas? Can the navigation controller expose properties to all of it's embedded views?
Thanks.

Until recently I used Matt Gallagher's synthesize singleton to do the same thing you mention.
However, recently I converted my project to use ARC, so the singleton setup simplified somewhat. Now I have:
static MMPersistentStoreController *sharedMMPersistentStoreController = nil;
+ (MMPersistentStoreController *)sharedMMPersistentStoreController {
if (sharedMMPersistentStoreController == nil)
{
sharedMMPersistentStoreController = [[self alloc] init];
}
return sharedMMPersistentStoreController;
}
I think this a pretty standard approach. Certainly it's better than passing the object around everywhere.
As for alternatives, I guess you could synthesize it as a property of your application delegate then access it via UIApplication.
With the former approach, it's a static instance created by the MMPersistentStoreController class object. With the latter, the instance is is an ivar of an object that will only ever exist once in your application.

Related

Keeping an updated model class and accessing it from multiple view controllers in Swift?

I am making an app with swift and xcode. In it I have a model class with user's information in it. I want to display some of that information with one view controller, update/change that information in another, and keep all of the views up-to-date with whatever is in the model class.
I was told using a singleton could work but is not recommended. Is there a better, more accepted way of accessing the model class from multiple view controllers without a segue between them (I am using a tabBarViewController)?
If you want to go "pure" that is follow Apple Best practices where a View Controller is never hard-coded to a global model (more of a pain than is worth, practically, in my opinion):
Subclass UITabBarController to contain the model instance as a stored property (perhaps private(set) is the best access level here, but however you want to expose it safely to other classes -- PUBLICLY EXPOSED AS A PROTOCOL TYPE ONLY OF COURSE.)
Don't forget to set the identity class of your Storyboard Tab VC to this new subclass otherwise your sexy code will not run.
In your (hopefully base class to all child tab VCs) View Controller class, hook into didMoveToParentViewController(parent: UIViewController). Gently downcast (as?) to the UITabBar subclass above, and extract the model, and copy the reference into your local stored property. It will happen exactly at the right time, just as you land into the soft arms of your parent VC.
Happiness!
You can try KVO mechanism. By which if you change a model variable's value that will reflect in another controller. For your reference
https://www.appcoda.com/understanding-key-value-observing-coding/

Present View Controller without being on a View Controller - Swift / Objective-C

I'm creating an app that implements a Facebook and a Twitter service. In my view I have a button that toggles sharing on Facebook/Twitter or not. If Facebook/Twitter aren't connected, then the button will show "connect to".
When I click the button, a method in my controller (not my viewcontroller) will try to toggle the value because this controller tracks the state of my app. When I'm not connected to a social network my controller will notice and will call the correct service. This service will start a webview to provide the user credentials.
And now my question:
When I'm in my service and I need to provide credentials via a webview. When I want to show this webview I need to pass a View Controller that will handle the presenting. How do I provide a viewcontroller here?
Approaches I found:
Call the appdelegate singleton and get the current presenting
viewcontroller (I find this dirty but correct me if I'm wrong).
Since I'm injecting my service into my controller in
appdelegate.didFinishLaunchingWithOptions I could inject the UIWindow
of the appdelegate and ask for the current presenting viewcontroller
(Is almost the same as the first approach)
Create a protocol implemented by a viewcontroller. The service has a property that is equal to that protocol and in my app delegate inject the
viewcontroller into the service.
Have a property in your controller
that will be the presentingviewcontroller and let your controller
implement the approach #3 protocol. When a function of that protocol
is fired, the controller will handle it and use the
presentingviewcontroller property for the webview. I only need to
inject a viewcontroller into my controller in the appdelegate.
Don't implement anything view related in that service.
My current implementation is approach #3.
If some things are not clear, please let me know.
Any help is appreciated!
Thanks in advance!
I was hoping this question would of got more attention, I was interested to know how other people would handle this situation.
As you have already stated, there are a few ways to achieve what you need, but the answer depends on having knowledge of the application.
I would definitely try to keep business logic and UI as separate as possible, there are two methods that I can think of to do this, but they are pretty much the same thing.
Make the (non UI) controller responsible for the login check with a callback function, you can then leave the controller responsible for business logic and the calling ViewController responsible for rendering any UI as a result of that check.
As you suggested, using protocols, your controller could have a delegate that will be a ViewController that conforms to your protocol. Then usage would just be getting your shared instance, setting the delegate and calling the required fuctionality.
I would likely favor option 2 to be more Swift-like as it is a protocol orientated language.
If the controller is acting globally and accessed from anywhere within the application you could potentially end up duplicating a lot of code to make these checks, you could get around this by creating an extension of UIViewController which provides the functionality to interact with the controller.
I hope this helps, Would definitely be interesting to see the way other people would approach this.

How can viewControllerWithRestorationIdentifierPath:coder: find an existing instance?

The docs on viewControllerWithRestorationIdentifierPath:coder: say:
Your implementation of this method should create (or find) the
corresponding view controller object and return it... It is not always
necessary to create a new view controller object in your
implementation of this method. You can also return an existing view
controller object that was created by another means. For example, if
the view controller had already been loaded from a storyboard file,
you would return that object rather than create a new one. [My italics.]
This has always seemed like complete nonsense to me. This is a class method! We don't have any access to any instances at this moment — unless we create one. I'd be grateful if someone can explain to me how on earth a class method can find or know about "the view controller that has already been loaded from a storyboard file".
EDIT: To earn the bounty you must show me an actual case, from your own app, of the class method viewControllerWithRestorationIdentifierPath:coder: being used to "return an existing view controller object that was created by another means."
The most common example of this I can think of is any of the view controllers that are owned by the App Delegate. This is traditionally a tab bar controller or a navigation controller in traditional apps, but sometimes it can be something completely custom, which is when this functionality might be useful.
Since the UIApplication is pretty much a singleton and has one delegate, it means your App Delegate has global state, which makes it accessible from anywhere, including in class methods with: [[UIApplication sharedApplication] delegate].
Of course, any singleton is accessible from anywhere and a common pattern (but one I personally dislike) is to have a NavigationManager singleton which manages any global view controller transitions, so in this case you'd be able to access the existing instances as well.

iOS storyboard and injecting properties

I'm using iOS 5 storyboard for the view control hierarchy. The problem with this is that I have a few shared controller classes that handle the business logic that I would need to inject to the view controllers. These controllers are initialized and kept in the app delegate.
For instance, I have a controller encapsulating Dropbox interaction that I'm using in some of my view controllers. I could pass the reference on with each prepareForSegue:sender: but this makes the whole view controller hierarchy dependent of the controllers. Also, I could use the singleton pattern but I'm not really a big fan of it.
What are my options, if I want the controllers loosely coupled? I've heard of Objection, and I'll be looking into that, but any input would be very welcome
I know this is a bit late but hopefully it can help others.
I solved this problem using protocols and checking the object to be injected responds to certain selectors.
In the prepareForSegue method I do one of two things:
id object = segue.destinationController;
if([object conformsToProtocol:#protocol(HasApplicationManager) ]){
[(id<HasApplicationManager>)object setApplicationManager:_applicationManager];
}
if([object respondsToSelector:#selector(setViewDelegate:)]){
[object performSelector:#selector(setViewDelegate:)withObject:self];
}
The first bit checks if the destination controller conforms to a specified protocol, this is still loosely coupled because you build your application with the composition pattern.
And secondly i check for a selector, this is more informal than protocols and probably more coupled and presents more problems. But it is a way of getting around having hundreds of 'IHave...' protocols.

iOS: better design with UIViewController parent-children classes

I have a parent class DocViewController (inheriting from UIViewController) and 2 subclasses:
PhotoViewController
MapViewController
In the parent class (DocViewController) I have the following code:
if ([previousView isKindOfClass:[PhotoViewController class]] || [previousView isKindOfClass:[MapViewController class]]) {
[viewControllers removeObjectAtIndex:[viewControllers count] - 2];
self.navigationController.viewControllers = viewControllers;
[viewControllers release];
}
That I'm using to delete the children classes from UINavigationView stack. (It is not about the question anyway: I have a segmented control and I'm pushing such classes, but I still want my "Back" button to ignore them).
It works. My only problem is that is not very object-oriented since the parent class import the children for the if statement. Right ?
thanks
Yes, it's not very object oriented. Would be better to implement a method on the classes. Maybe something like
-(BOOL)shouldPopTwo;
and then
if ([previousView shouldPopTwo]) { ... }
And then each subclass can implement as it needs to.
BUT
In most cases I think you should avoid the temptation to build class hierarchies with UIViewControllers. Controllers are typically the least reusable objects in an MVC setup as they are designed to very specifically define behavior and map it to specific Model objects. Certainly hierarchies can be built (As they have been in the SDK), but the structure, function and abstraction needs to be very carefully planned and constructed.
Instead, you should probably create reusable UIViews and then implement different UIViewControllers to define how the application should use and respond to those views.
In response to comments below:
Sounds like you might be trying to use a navigation controller in a way it wasn't intended for and actually your last two view controllers should be a single view controller. A view controller is primarily intended to manage a full screen's worth of content. If I understand correctly, in your case you have a segmented control that should stay on screen and be responsible for switching the content in the rest of the available space. I would suggest you have a single view controller and it's view would contain the segmented control and a 'canvas' which would be used to display alternate views. The view controller would hold references to the views it is managing so that it could switch them in and out (if you want UINavigationController-style animations you'll have to implement that yourself).
Finally, you would need to decide: Can this single view controller act as the controller for the two subviews? Or should each view have its own controller? If this UIViewController subclass is a one-off, and it is only intended for these two views (say PhotoMapViewController) you could choose the first, easier option. If you want this to work with any UIView (say SegmentedControlViewController), then each view should have its own NSObject controller (not UIViewController). From the apple docs:
Note: If you want to divide a view
hierarchy into multiple subareas and
manage each one separately, use
generic controller objects (custom
objects descending from NSObject)
instead of view controller objects to
manage each subarea. Then use a single
view controller object to manage the
generic controller objects.
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/AboutViewControllers/AboutViewControllers.html
But that would require substantially more abstraction and setup.
If the overall goal is to (I'm guessing) map a collection of photos, in the first case in the calling view controller you might have code like:
NSArray *photoCollection = model.myPhotos;
PhotoMapViewController *pmViewController = [[[PhotoMapViewController alloc] initWithPhotoCollection:photoCollection] autorelease];
[self.navigationController pushViewController:pmViewController];
and PhotoMapViewController : UIViewController would be responsible for creating and initializing the two views its segmented control manages.
I won't go into the code of the second case because it's much more elaborate.
Finally, look to the OOP principle of favoring composition over inheritance to see a broader perspective of why you might do things this way instead of your first implementation.
Any time you start to set up a class hierarchy you should ask yourself - Is it really a subclass? and then stop and ask yourself - No wait, is it REALLY a subclass?? :) Good luck!

Resources