Best Practice: Accessing instance of UIViewController from another in iOS - ios

I have a navigation controller with 4 view controllers on the stack. I need to access a function in ViewController1 from ViewController4. What is the proper way to do this?
Do I pass the reference to ViewController1 through ViewController2 & 3 then access the function using a protocol delegate?
Do I store a reference to ViewController1 in a struct then access it from there?
Number 2 is what I am currently doing. I set the reference when I leave ViewController1 then set that reference back to nil when I'm done with it.
Why I need to do this:
VC1 has a tableview with a bunch of items. The data in these items is edited in VC4. Once editing is done in VC4 I want to save, pop to root, and reload the tableview with the new data.

Your plan is all wrong. What you should be doing is have a data model that can post notifications about changes in its data. There should be no link whatsoever between the view controllers. VC1 should be prepared to listen for notifications from the data model. When VC4 updates the data model, the data model will tell anyone that is listening that it has been updated.
With this setup, any number of view controller can all be listening to the same instance of the data model being passed around. Any part of your app can respond as needed to these notifications. The best part of this design is that no class has any knowledge of any other specific class except everyone knows about the data model.
The data model has no knowledge of any controllers or views.
No controllers have any direct link to other controllers except for one that needs to present another.

I think you can use notification. Make VC1 to subscribe the notification. When need, in VC4, send the notification.

Related

good ios design with mutiple controllers

I intend to build a rather complicated app and I am wondering how to design it correctly.
I have a rootcontroller that is in charge of dispatching the creation of several Controllers (VC1 to VC5), each of them associated with its own storyboard.
So each of these storyboards are quite complex with several levels of controllers usually driven by a navigationcontroller.
My question is the following : let assume that the user is using the deepest controller in the storyboard of VC1. In this controller there is a button. When the user click it I want VC1 and all the controllers linked to it to close and also to have some data sent to the rootcontroller.
My idea is alse to be able to reuse VC1 to VC5 somewhere else in the app but from a different controller than rootcontroller.
What is the best design to achieve that ?
Thks
First off, there is no best design.There might be better design in this world for everything.
Your First Quest:
You can use Tabbar Controller with 5 Tabs.
Each tab will have navigation controllers for holding your complex design.
For data passing:
Unwind Segue.
Delegates.
Notifications.
For your quest :
user click it I want VC1 and all the controllers linked to it to close and also to have some data sent to the rootController.
There are many tutorials of how to go back to root view controller along with data.One of them is passing-data-between-view-controllers
I don't want to elaborate this whole procedure but the theme is.
One of many solutions:
Assign that data to destination VC' variable before moving to that VC .For navigation controller, to move to rootView controller,
[self.navigationController popToRootViewControllerAnimated:YES];
is used. Hope i've given some light. :)

iOS object or delegate between two controllers?

Evening, my question is full about theory.
I understood reading from Apple developer documentation that is better to use the Delegates Pattern to keep track of some object attributes. In this way we can access the delegate without access to the object. (I really didn't get the reason of this choice)
I also understood that is better to define: protocolDelegate: class
and when we are declaring the delegate inside the class it's better to use the weak word to prevent some "kind of problem cycle". (??)
So, while I was playing a bit with code, I've discovered that you can't pass a weak delegate between two view controllers, because of course, when you change the controller, the weak delegate is going to be deleted because is a weak thing (or at least this is what I understood).
So, I have to choose between 2 options:
make the delegate "strong" deleting the weak key.
or pass the object in the segue and keep the delegate as weak.
I have a lot of confusion, can you clear my mind? :D
The cycle you're referring to is called a retain cycle.
Let's use a concrete example to clear this up: say you've got a UIViewController which has a UITableView. The view controller has a strong reference to the table view. The view controller now wants to act as the delegate to the table view.
Now, if the table view would have a strong reference to its delegate, we would have the following situation: the view controller has a strong reference to the table view, and the table view in turn would have a strong reference back to the view controller. Thus neither can ever get deallocated.
To break this cycle, references to delegates are usually weak. This allows the retain count of the view controller to drop to 0 eventually, which can in turn release the table view.
Your classes that want to use delegates should also follow this pattern and use weak references to their delegates. You should thus pass the required references via your segue.
I will concentrate on the first part of your question, since the previous answers have covered the rest pretty well.
Consider the following situation: you have a class that handles some kind of network connection - it sends a request to a server and gets a response. Outside of this class there is a viewController that has a button that triggers the request and a view which presents the response to the user.
Basically, the network handling class should be able to get some message from the viewController (button pressed) on one hand and pass the viewController the response on the other. So there should be bidirectional communication between the two classes. While the passing of the buttonPressed message to the network handling class is pretty obvious, the reverse part (passing the response) is a bit more tricky, because the network handling class should not be aware of who created it and who calls it (good OO practices and memory leaks prevention).
That's the point where the delegate pattern comes in. It allows an object to pass data to whoever is interested in it without knowing anything about the recipient. The class that passes the response only knows some 'delegate' and not another class. In addition you can take out the network handling class as is and put it in another project. Because it isn't supposed to know any other class from its original project, only some 'delegate', it can be put into another project without any modifications.
I hope it can help you to get the reason of the choice.
I think pass the object with segue, Segues are a very important part of using Storyboards in Xcode. We can go over the different types of seguesanother time, but this one shows you how to use the “Show” segue, as well as how to pass data between the two view controllers to customize the second one with whatever custom data is required.
You can easily use segues example; Under below you can send currentstring to destinationViewController inside sentstring , also ShowSegue is your segue identifier
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowSegue" {
if let destinationVC = segue.destinationViewController as? OtherViewController {
destinationVC.sentstring = currentstring
}
}
}
Navigation between viewcontrollers maintain stack of viewcontrollers.
For example aVC is firstviewcontroller then top of stack will be aVC,
now when you push or show another viewcontroller say bVC then now top of statck is bVC. So stack looks like,
aVC -> bVC(top)
now you push another cVC then,
aVC -> bVC -> cVC(top).
So top of stack is always visible to user.
at current situation, aVC and bVC and cVC are not deallocate. they are in memory. But if you pop or dismiss cVC, then it will deallocate from memory and now your top of stack looka like,
aVC -> bVC(top).
So viewcontrollers live in stack till they are not popped or removed. So, they are strog reference by default.
Segue is nothing but you can say that they are graphical representation of push or pop operation.
another thing is that delegate should be weak that because it can create retain cycle if they are strong.
you can called delegate as representative in general sense.
Now, if you are using segue, send your object in prepareForsegue and it will manage everything else.

Reactive Cocoa limit a signal to only one subscriber at once

I need to model following in RAC.
I have a tabBarController which will subscribe to a notification signal. Say push notification. Also say currently active view controller may also be want to subscribe to the same signal. But if any view controller subscribed to it tabBarController doesn't want to handle it. Otherwise it will handle it. Also when current visible view controller changes. It needs to delegate back the responsibility to tabController.
Currently without RAC I maintain array of observers at tabController. If any observer present for particular kind of notification. It will delegate to viewController otherwise tabController will take care of it.
Any better way to model this using RAC?

How to use shared Instance of UIViewController in Xcode?

This might sound like duplicate, but I need farther understanding and explanation about my Scenario please.
In my app, I have one InfoViewController, which represents information when called (pushed)from other Controller like, 1)HomeViewController, 2)FavouriteViewController and 3)DownloadViewController. All 3 held by UITabViewController
InfoViewController had about 10 buttons and corresponding actions. I use separate singleton to hold all info objects.
All 3 ViewController(Held by TabVC)--> Loads object to Singleton --> InfoViewController uses that to Present Detail Info
HomeViewController - Its for new 'Info' to present,which changes everyday
When Information is present,
user can mark it as a Favorite, which then Listed(In UITableView) on FavoriteViewController.
User can save it in phone for future reference, which will be listed(In UITableView) on DownloadViewController.
On selection of cell all 3 represents details using InfoViewController.
Now I want to present only one instance on InfoViewController to be visible to user. Not all in all 3 tab. Currently I am switching it back to Main screen with ViewDidDisappear method. Which works only when I add InfoViewController as child to main 3 VC. Not by push.
Now my problem is, i tried to use Appdelegate to initialized SharedInfo Object
sharedInfo = [InfoViewController alloc]init], but it goes to black screen. I have to initialize it as
[self.storyboard instantiateViewControllerWithIdentifier:#"InfoViewController"];
but this is not allowed in AppDelegate or making shared instance on InfoViewController itself.
How do I achieve Only one Instance present to user at a time??
I think rephrasing what you need might help. I don’t think you really want a shared instance of the UIViewController. What you want is a single source of the data which is displayed in one or more views and a method to update that data in all the views when the data changes.
Two possible solutions are:
NSNotification
Any view which contains the shared data subscribes to notifications when the data is changed. When data is updated via the singleton it sends a broadcast to anyone listening to update the view data.
View Lifecycle
In this second method the data in a particular view is only updated when the user brings up that view. Note in a tab bar interface that the viewDidLoad is called when the view is initially loaded. DO NOT update your data here if it changes. Instead you want to update the data in viewWillAppear as this is called every time you navigate to that view. In viewWillAppear you have code that checks the data and updates it if needed.
There are other ways to skin this cat, but either of the two above should work for you.

Best Practice? Passing object References back from segues

Good morning.
I have been working through a lot of tutorials the past year, and have seen several methods of passing reference back up the View Hierarchy with Storyboards. I was wondering what some best practices are, and more importantly any pitfalls using the following methods:
Protocol - the child view implements a protocol, that the parent view sets itself as the delegate to and responds to messages. This can be used to pass back information to the delegate. The Child does not need to know anything about the reason it was called, it does it's job, and sends back whatever information it was asked for.
Public property of the Child ViewController that has the model reference. On the segue you retrieve the reference to the destination view Controller. This view controller has the model property exposed publically. You pass in your reference to the model. I personally like this method - can't see any real pitpalls with it. then when the child makes changes the model is changed directly. at the point [self.navigationController dismissViewControllerAnimated:YES] gets called to or however you navigate off/dismiss the view controller you have the information in the model you want.
ANYTHING ELSE? - someone else has a good idea, i'd love to hear it.
Thanks for anyone's input on this. I know there are always more than 1 way to skin a cat, I just want to skin the cat cleanly and quickly. (-Sorry cat)
Steve
For the sake of completeness, in addition to the two options you enumerate, there are a couple of other options:
Use unwind segue (iOS 6 and later), and you can pass data to the "destination" (the controller you're unwinding to) via prepareForSegue;
Use singleton for your master model object;
Use Core Data (or SQLite) for persistent storage; or
Use notifications or key value observation (though this is much better for communicating data updates to multiple objects).
Personally, I'll generally use a protocol when it's just a matter of a presented view controller wanting to inform the presenting view controller of some information, but each of these techniques have their respective uses.
Depending on your need there is another option and no segue is required.
The child view controller could create its own object or obtain a known shared reference of any object. Creating its own object would be good for adding a new item to a table. Obtaining a known shared reference would be good for something like a settings object.
When the child view controller is ready to be dismissed it posts a notification.
[[NSNotificationCenter defaultCenter] postName:MyAppDidCreateNewItem object:self.item];
or
[[NSNotificationCenter defaultCenter] postName:MyAppDidUpdateSettings object:self.settings];
The parent view controller registers as an observer to the notification. When the notification happens, the parent view controller can use notification.object to get the reference and update itself.

Resources