I followed this discussion: UITableView issue when using separate delegate/dataSource, and even though I found it super informative and useful, I have a follow up question:
So I've got a similar setup where I have a UITableView within the UIView. The UIView is controlled by it's own UIViewController (let's call it MyUIViewController) and also I moved the delegate and datasource for the UITableView into a separate subclass of UITableViewController (say, MyUITableViewController).
Everything works fine with the tableView.
The question is, how do I make a callback from MyUITableViewController to the MyUIViewController? For example, if the user selects a cell under the tableView which triggers didSelectRowAtIndexPath, I need to update something on the UIView which is actually a parent of this UITableView. So I basically need to send a message to MyUITableViewController. How would I do that?
You can use a delegate pattern in this case. I have a similar answer with sample code in this SO . In your case, the parent view controller is MyUIViewController. And the child view controller is MyUITableViewController.
Related
I'm learning swift and I have gone through tutorials where some developers delete the View Controller entirely and just drag in a TableViewController and start using that. While other developers in tutorials create a TableView from within the View Controller.
Is it better to delete the View Controller and add a Table View Controller or just work with a TableView within the View Controller?
It is all about the requirement. Both are correct way. Don't be confuse.
When you using TableViewController then it only behaves with the UITableview. i mean controller totally dedicated itself as tableview.
When you using TableView inside UIViewController then you can create whole UI deign in your own way.
Note: As you'r new so I suggest you to go with TableView Inside UIViewController because you can achieve any type of UI with this even you can create ditto functionality(UITableViewController) with this but vice versa not true.
For eg.
tableView inside UIviewController
You can do it in either way. If your viewcontroller is going to have a tableview alone, then u can use a UITableViewController or else use UIViewController and set the delegates and datasource
I'm learning Swift. Sometimes I see that Main.Storyboard is used to set up the tableView delegate and dataSource (ctrl+click and so on). Sometimes I see that it's done through coding instead like so:
// create the variable for the tableview
IBOutlet weak var someTableView : UITableView!
// setup delegate and datasource
sefl.someTableView.delegate = self
self.someTableView.datasource = self
I do understand how it works with second way. But it's difficult to realize how it works through Main.Storyboard with no IBOutlet setup.
Thank you for your responses!
It works exactly the same way :)
Let me refresh the principle:
You have a class, provided by Apple in this case, that has to work for a lot of scenario. Apple decided to use a kind of inversion of control, called delegation, where the workflow is inverted (hence the name) : instead of the view controller giving order to the tableView by calling methods on it, it is the tableView that goes and fetch its orders from the controller by calling methods on it.
In order to achieve this kind of IoC (inversion of control), the TableView MUST know the "address" of the object it has to ask for its order. Like you have to know your boss' email address to ask him stuff. So, the UITableView class as a property called dataSource that means to store that address.
Now as a ViewController programmer, you have to set this property to be the address of the view controller that will give the order to that tableview.
2 ways of doing it :
in code : in the view controller, you have a property pointing to the tableview (if linked from the storyboard, it is called indeed an IBOutlet, but doesn't have to be) and you set it's delegate property to self. (meaning 'hey tableView, your boss is myself)
Or you do it in the storyboard, because the graphic template for the tableView let you ctrl+drag from the tableView to the ViewController and set the datasource connection. In this case it will be the storyboard who will have to find the address of the tableView (since it is the one creating it, it's kinda easy) and setting it's delegate property to be the address of the view controller (meaning hey tableView, your boss will be this guy)
Either way, the viewController has to be ready to answer all the question from the TableView, so conforming to the UITableViewDataSource protocol.
the delegate scenario is the same.
It is important to understand how the loading of views works in iOS. Your xib will be translated into the hierarchy of views and they are loaded onto the memory. When you make an IBOutlet of those views, you'll have a reference of that loaded view in your code. If you do not create an IBOutlet, it doesn't mean that the view isn't there. It is there and it is in the memory.
When you set the delegate and the dataSource of a tableView and when the tableView is loaded onto the memory, it sets the delegate and the dataSource of the loaded tableView to the class as specified by you. It doesn't matter if you do not have a reference to it.
I have a reusable UIViewController subclass (an audio/video player, let's call it MediaController). It works ok when I add it to some other view controller as a child view controller, however my requirement is to also add it in a UITableViewCell subclass. Since -addChildViewController: is a method of UIViewController, I'm adding my view to the cell like that:
self.mediaController.view.frame = self.containerView.bounds;
[self.containerView addSubview:self.mediaController.view];
(containerView is just a placeholder view in the cell's view hierarchy).
However, this causes problems, first because MediaController is having some logic in -viewWillAppear and -viewWillDisappear (that of course never get called) and second because it seems that autolayout does not work properly when MediaController's view is added to the cell.
Do you think I have some other option (maybe use the UITableViewController that owns the cell as a container?) or I will not be able to use this MediaController at all?
This question is the most relevant when I search, but it still doesn't solve my problem.
Thanks!
One thing I might try if it's possible is to have a UITableViewController that has static cells.
If you're using a UIStoryboard drag and drop a UITableViewController and change the content to Static Cells then in the cell you want to have your MediaController drop a Container View into that cell. Then drag and drop from that Container View to your MediaController and setup an embed segue.
The appropriate viewLifecycle methods should be called when displaying.
Here is the UIStoryboard setup
The other answer from aahrens did not work for me since I have a complicated table view and I was not using storyboards from the beginning.
What I ended up doing was to pass a weak reference of the UIViewController to the cell, so that I can make the "normal" call to -addChildViewController:. Ugly, but works fine.
I want to break my code into 3 files and them up via addsubview. For ex. i have a masterview, mastreview contains a currentView. CurrentView contains 1 webview and 1 tableview.
Now, i have written all code in one file and it works like a charm. But i want to make it abstract and loosely coupled . So i need a separate file ex. webviewController to implement its delegate and function related to it AND tableviewController to implement its delegate and functions related to it. And add both by addsubview, alloc init in masterview file.
I did it my way,though i was able to addsubview on CurrentView, the problem was my delegate functions are not working properly.
Also, i am confused about tableviewController should inherit UIViewController or UIView or UITableView.
it would be good if anyone can guide or send some link related to it, any example...???
Actually you should have the app crashing if the delegates are not retained somewhere.
If you do link the object with view controller to be it's delegate at Interface Builder, the view controller will be destroyed after it's outlets so you don't care. If you are creating separate class for the delegate, you should care about it's lifecycle, standard classes do not retain their delegates so you have to retain it on the same level where you are retaining the delegated object. Like if you are creating a UITableView subview and you have MyTVDelegate class, you should create the delegate instance, assign it to tableView.delegate and retain as viewController var so that viewController will dealloc both subviews and their delegates when needed.
For the second question, UITableviewController inherits UIViewController as you can see at header files (command+click on UITableviewController), and UITableView inherits UIView. Every viewcontroller should have the root view of UIView and I believe UITableviewController has UITableView as it's root view.
I'm having a uiscrollview with 3 slots, each holding a tableview with different data.
As you can imagine, handling 3 tableviews on the same viewcontroller is a bit of a mess.
So I was thinking about using multiple uiviewcontrollers to handle the different logic required for each tableview. However I can't seem to do this since uiviewcontrollers load in a modal way/blocking the entire previous view: this leaves me unable to continue to use the uiscrollview placed on my root view controller.
Is there a way to solve this? Or pack UIView logic and behavior in some sort of stub/hidden uiviewcontroller that doesn't block the view below?
You are looking at this the wrong way. Separating your tableviews is a good idea, but there is no need to use a view controller.
Let's say you have three tableViews: tableViewOne, tableViewTwo, and tabelViewThree.
The problem (as I understand it) is that all of your logic code (datasource and delegate methods) are getting all mixed up. So, just create a subclass of NSObject for each tableView and use that object for the datasource/delegate. Just make sure you set the datasource/delegate properties of the tableView to the right object.