I have a UIViewController in my application that contains a UITableView. This tableView has a few different states for section 2. The rows in this section can vary by height, cell type and number of cells.
The way I used to handle this was one UIViewController with lots of different if-statements in the UITableViewDelegate and UITableViewDataSource. Now, after a while, this has given me quite a lengthy and complicated controller.
I thought about two possible routes to fix this. The first one would be different UITableViewDelegate and UITableViewDataSource classes, based on an if-statement. The other would be to load in a different UITableViewController for each of the possible states.
What do you guys think would be the cleanest solution? Or are there any other cleaner solutions?
Firstly create an extension for viewcontroller which confirms to tableView dataSource and delegate protocols.
To achieve this we can create a custom method in presenter class to handle all this code and call this method whenever required.
Related
I noticed in using UITableView, UICollectionView, UIPickerView, UIScrollView, ..., and numerous other UIKit classes that the UIViewController containing the object instance often bears the role of DataSource and Delegate.
I understand from Apple's documentation what these data source and delegate methods are called, and how to implement them... for a single instance of each class.
My question is, how do you handle different instances in the same UIViewController? For example, if I have two UICollectionViews, or three UIPickerViews, ...., or fifty UIScrollViews? I can implement the data source method only once per UIViewController, but I somehow have to tell the program different instructions?
The only thing I can conceive is a gigantic switch statement or a bunch of cascading if-else if-else comparing the input to the delegate or data source method to each object instance in the UIViewController, which might get out of hand if there are many.
While we're used to using our view controller as the delegate, there's no need to do so. You can actually create NSObject subclasses that conform to the delegate protocol in question. You can then instantiate those objects and use them as the delegates of the UI objects (or whatever) as needed.
For example, consider a scene where I have two text fields, one which permits only numeric values, and one that does not accept numeric values. I can write a separate delegate object for each type of text field.
If implementing this programmatically, I would manually instantiate the two delegate objects, keep some strong references to them in my view controller, and then in viewDidLoad I can set each text field's delegate to be the appropriate delegate object.
If doing this in Interface Builder, you can actually drag an "Object" from the "Object Library" onto the scene (either in the bar above the scene or the document outline to the left of the scene):
You can then specify the class for this object:
Repeat this for all of your delegate objects:
And finally, you can go to your text field and specify the delegate by control dragging to the delegate object you added to the scene:
Doing it in Interface Builder means that it completely takes care of the instantiation of this delegate object for me and I have to do nothing in view controller's code.
Bottom line, if you want distinct behavior for a UI object, you can just instantiate a separate delegate object that manifests the desired behavior, and use that as the UI object's delegate. This pattern of instantiating separate delegate objects is common in iOS 7 custom transitions (where we have all sorts of delegate objects banging about), but can be used in this context, too.
BTW, you can obviously just subclass the UI control in question, too, and further encapsulate the logic there. That works equally well.
By creating referencing outlet for each controller,for example if you have two UITableView ,You can create outlet for each such as table1 and table2. To set number of rows in a section for these table ,you can code like follow
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == table1) {
return 10;
}
if (tableView == table2) {
return 5;
}
return 1;
}
You can create independent UIViews for each tableView or collection view with it's own .swift and .xib (and maybe if they are very similar you can reuse them). Doing that you will have the tableView and collecionView delegate methods in separated files and everything will be more clear. In your view controller you will just have to place the views, but you won't have any delegate methods there.
Well you are asking to differentiate the views with datasource & delegate in a smarter way. But you are overthinking this thing.
Everyone takes the different tableviews or pickers because they wan't be the same.
Otherwise they can be reused.
Now if they are going to be different from others then ultimately somewhere in your code you have to put the if...else or case statements. For example for tableview while setting the value of an UILabel or any value in your UITableViewCell.
If you are facing a such an issue that you have to put that many scrollviews or something in only one UIViewController then its an impossible situation if you are following the coding standards or may be your app design is faulty.
In my iOS app I have a view controller and a UITableView subclass on one of my views. Currently the UITableView manages it's own data (creating connections, and being the delegate which handles the callbacks).
I was wondering if this is best practice? Is it better to run this on the view controller and then pass the data into the table? Does this not matter at all?
Please explain the reasons in addition to answering my question.
Thanks!
It would be more standard to implement the delegate and dataSource methods in the ViewController.
It is quite unusual to subclass the UI*View classes, except to customise drawing. UITableViewCell is a bit of an exception to this rule.
If you find your ViewController getting a bit big you might think about implementing the delegate and dataSource in a separate class.
In addition to mcfedr's answer, views are things that interact with user and it is generally good to separate concepts (unless unavoidable). Also note that historic versions of ios (iirc) view controllers may load/unload views on demand, so any application logic in there may cease to exist.
In this scenario, I generally have only one class... The UIViewController instance that contains the following view hierarchy:
view -> myTableView
With this approach, my UIViewController will:
Have an IBOutlet to a UITableView (myTableView)
Implement methods of UITableViewDelegate
Implement methods of UITableViewDatasource
Set myTableVIew.delegate to self
Set myTableView.datasource to self
When the host UIViewController is the delegate and datasource of your UIViewContoller, all code can exist in one class. This keeps the code of your project tighter but does tightly couple your logic.
The alternative approach would be to subclass UITableView and implement UITableViewDelegate and UITableViewDatasource. This will be a desirable approach if:
You wanted to reuse the UITableView in multiple UIViewController
You wanted to encapsulate the UITableView logic from the UIViewController
Here is the thought process I use:
Am I going to reuse this UITableView and its logic?
Yes -> UIViewController class and UITableView subclass
No -> UIViewController class only
The best practice would depend on the number of programmers involved, the repeatability of the UITableView, coding patterns already established. This is often a matter of preference and I hope my answer shed some light on why you would go either way,
I've got a static TableView that now needs to become a dynamic TableView, because other views need to be placed around the ViewController, and this can not be done using containers in my case.
The question is: how do I efficiently convert the table view from static to dynamic?
I'm aware of having to change the inheritance from UITableView to UIViewController and add the plus the delegate methods.
But how about all of the Table-Sections: I have 3 sections with 6 types of cell in the static table. Do I really need to subclass UITableViewCell for all of these cell-types and deal with everything manually, or is there a more clever way to do this?
You really can't just convert between the two. By merely implementing some of the tables delegate methods, like cellForRowAtIndexPath:, you loose your static content. That being said, the table should be dynamic the entire time. This way, you can define logic to determine whether or not it should show the content that you originally added statically, or the new dynamic content.
Additionally, you don't need a view controller to implement the delegate/datasource methods. If you already have a subclass of UITableView, that's fine. You can set it as its own delegate/datasource, and implement those methods within the subclass.
And to answer your last question, no there really isn't a better way to do that. I recommend that you create one base class that subclasses UITableViewCell that implements everything that the cells will share, and then implement the individual changes in subclasses of this base class. Using multiple cell subclasses in a table view sounds a lot worse then it is.
According to the Model-View-Controller pattern, applied heavily in Cocoa Touch, UIViewControllers should always handle the logic behind how a concrete UIView in the scene behaves.
I am curious as to how Apple implements it's UITableView class while keeping in line with this philosophy. Especially since UITableView inherits from UIScrollView and UIView in turn.
When you add a UITableView to one of your classes, does it have a UIViewController handling the way it behaves in the background? I know that a UITableViewDelegate is in charge of telling the table how many rows it should have, etc. But what about it's inner workings?
I'm gonna take a wild shot here, because I'm not sure I really follow your question. When you add a UITableView, you HAVE to have a controller associated to it to control how it handles and renders. Either a UITableViewController or a UIViewController that implements UITableViewDelegate and UITableViewDatasource. If you don't there's no way you can control what it does.
I have a MainViewController, and I want to add two UITableView's to it, each with different cells. But I don't want to clog up my MainViewController code by checking in the table delegate methods which table it is, and then acting on it. It gets too messy.
So I thought I would subclass UITableView and let it handle the cellForRow and other table methods by itself, and this way when I want to add a table to MainViewController, all I'd have to is
CustomTable *customTable = [[CustomTable alloc] init];
[self.view addSubview:customTable];
and all the delegate methods would be handled in that class, leaving my MainViewController clutter free.
Am I approaching this wrong? Should I be subclassing UITableViewController instead? What's the difference?
When to subclasss UITableView? Not now.
Create two classes, which are member variables of your view controller. Point the table view delegates at each of your two new classes.
In Cocoa you tend to combine classes rather than inherit from them as you usually do in Java and C#.
In 3 years of professional working as a objective-c programmer, I didn't need to subclass UITableView once, the patterns, cocoa is depending on, — MVC and delegations (with using protocols), are just simple yet strong enough. And populating a tableview is just one of the best examples.
Make sure, you understand all this topics, as otherwise you will find yourself fighting the framework constantly.