I am using the UIViewControllerContainment feature in iOS. My container controller is called mainViewController. It consists of menuViewController and contentViewController. The menuViewController is a UITableViewController.
Now, I want that when I select a row in menuViewController I handle an event inside the mainViewController. I have to do all of this without changing the code of menuViewController.
** I am aware I can use delegates to call the mainViewController but using the delegate will alter ** the menuViewController code which I do not want to do.
Assuming that the menuViewController isn't designed with some sort of delegate or callback block (or you wouldn't be asking the question), you're options are really very limited, and there are no good options, since any option would violate the concept of containment that you're trying to take advantage of.
As I see it, your choices are:
Modify the menuVieController to add a delegate or block callback on item selection. This is the best approach since it keeps the menuViewController well contained and isolated.
Subclass the menuViewController, override didSelectCell... and do number 1. Probably need to make sure you call super as well. This is bad because you're making assumptions about the internal structure of menuViewController and violating containment.
Steal the tableView delegate and handle it yourself. This makes even more assumptions about the internals of menuViewController.
Bottom line, I'd really recommend you rethink the decision not to change menuViewController.
Related
I'd like to know which one approach is better and why. When passing data, do you use the delegation pattern to pass data between VCs or you create the destination VC in the prepareForSegue from the VC that you are making the segue and setting the modified data directly from that vc? I'm currently using the delegation pattern, but many people I see are accessing and setting variables directly in the prepareForSegue method of the destination VC.
There isn't really much difference. Passing through prepareForSegue is a simpler option, but if not done correctly can create bad links in your app.
prepareForSegue only passes information, but delegation calls delegate methods.
Delegation mostly leaves everything for the delegate to do.
Delegate methods can be called at any time, but prepareForSegue, as the name suggests, is only called before the segue.
Basically, they have the same effect, but take different paths to the effect.
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.
I am trying to pass instance of object from "initial" view controller to "item1" and "item2". I would like to avoid subclassing UITabBarController as it would make containment view controller know "too much".
Is there any good approach to do that using storyboards or code besides subclassing UITabBarController?
I would like to avoid subclassing UITabBarController as it would make containment view controller know "too much".
You should subclass, and your subclass should implement a specific protocol for this purpose. Yhen, the containing VC only knows about that protocol and it's appropriate because it has that direct responsibility.
I am trying to pass instance of object from "initial" view controller
to "item1" and "item2". I would like to avoid subclassing
UITabBarController as it would make containment view controller know
"too much".
The problem here is that the destinationViewController of your segue is the UITabBarController and not item 1 or item 2. This makes your case quite difficult if you don't want to subclass it, because you can't communicate directly between the instances of your initial VC and the two items.
My recommendation indeed would be to subclass, that's the right way to go in this situation (you might want to add a protocol that specifies the communication interface).
Other options are:
somehow give the initial view controller access to instances of item 1 and item 2 (you'll have to do a lot of this setup in code since Storyboards don't give you the power to do it all completely in IB)
use NSNotification and pass the instances as userInfo (not very elegant but might be the quickest solution for your isse)
store serialized versions of the instances that you want to pass in NSUserDefaults and load them in item 1 and item 2 (might be a lot of overhead)
I'm rather new to programming and wondering about a certain (best) practice:
Let's assume we have an app with several view controllers. In our case, most of those need the functionality of alerting the user about certain circumstances, make use of an activity indicator or depend on other similar general functionality. So far I've learnt how to implement such methods but then just copied the whole bunch of code to each view controller when needed. Doing so, every view controller gets filled up with a lot of extra code. I know it's possible to make code kind of "global" by moving it to the top of a view controller, outside the class brackets. But as we need to ensure that certain subviews are added to the right view controllers when calling those methods I'm not sure yet what the best way to go - in general - would be.
Is there a commonly used practice that differs from my approach when defining such - let's say - alert behaviors (defining variable/constant and its needed methods) which are used in multiple view controllers?
Objective-C provides two general ways of reusing code:
Inheriting a base class, and
Using a shared function.
The first case is straightforward: if you need a specific functionality in several view controllers, make a base view controller with the shared methods, and then derive your other view controllers from it:
#interface BaseViewController : UIViewController
-(void)sharedMethodOne;
-(void)sharedMethodTwo;
#end
#interface FirstViewController : BaseViewController
...
#end
#interface SecondViewController : BaseViewController
...
#end
#interface ThirdViewController : BaseViewController
...
#end
The second case can be implemented either as a helper class with class methods (i.e. with + instead of -) or with free-standing C functions.
You should look to see what could be moved from the controller level to the view level. It sounds like you're reusing a bunch of views so I would create subclasses of UIViews that can implement themselves. Then in the view controller you can handle when the views should appear and the data associated with them but you don't need to rewrite how to implement the views.
The way I am designing my code, with several view controllers, that interact, I have the need to pass data between the view controllers. The way that I am doing it is to "pass a reference", make a pointer, to the target view controller in as a method argument like below:
-(void)aMethodToSetUpInterfaceElements:(UIViewController*)targetCV
Is there anything wrong with this, or do I need to watch out? It works well on a functional level, but what about the design?
There's nothing really wrong about this.
If it works for you, than it's ok. Just make sure to have a weak reference to the view controller, otherwise you could have a memory leak with retain cycle. Read this for more information: http://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html
Speaking about design, it's really depends of each case. I could't say preciselly because you didn't give more informations about the funcionality that you are trying to achieve.
Maybe if you want to make your code more generic, to be used in other places or projects, you might consider to perform a delegate to your view controller, but this depends of your views hierarchy and its design. To see more information about passing data between viewControllers, please see this: Passing Data between View Controllers
I don't think it is a good idea to pass a view controller in order to transfer its data if you don't have enough reasons. I tend to exposing the minimal knowledge to another object.
For example, say you have two view controllers controllerA and controllerB.
If all you need is just to pass some data from controllerA to controllerB, you pass the data, which might be a NSData, a NSArray, a NSDictionary or your custom data structure. You should not pass the whole controllerA as an parameter to controllerB. Although you can access the data by using the controllerA.data getter, you have exposed too much knowledge about controllerA to controllerB, which may unconsciously ruin your design by increasing the coupling between controllerA and controllerB.
If you are aiming at handling the view transitions, that may be a good reason to pass a view controller as the parameter. So that you can make good use of its -presentViewController:animated:completion: to present a modal view, or push it into a navigation controller, or you probably want to get a reference to its view property and customize your own UI presentation.