Migrate UITableViewController to UITableView - ios

I currently have a UITableViewController, but would like to add a label at the bottom of the screen. I think the easiest way to do this would be to just use a UIViewController with a UITableView. Is there an easy way to migrate over? I've noticed some functionally is different; for example UITableViewController has a numberOfSections method, whereas UITableView does not have that method. Also is it possible to use a UIViewController as the delegate for a UITableView? Thanks in advance.
Update: I have attached a picture of the code, and the error given when trying to implement UITableViewDataSource.

You can do this. You need to implement the UITableViewDelegate and include the UITableViewDatasource in your View Controller, then you can use the functions you were using in your TableViewController.
Basically what you should do is add a tableview in the interface builder, or programmatically (depending on your choice). If it's done through the interface builder then outlet it to your Controller. Add the Delegate to your class, and you would have access to the tableViewFunctions (cellForRow, numberOfItems, numberOfSections, didSelectRow etc...).
Also, when you create the tableview specify the tableview.delegate = self and tableview.datasource = self.

As far as I know, the methods are the same, you just won't need the override bit before each one if its just a UITableView. You can use UIViewController as the delegate, yes, by setting myTableView.delegate = self in its viewDidLoad method.
If its just a label you need however, you might consider adding one programatically? Similar results achieved with a no data label for example - see here. You could then play around with the positioning.

This error is thrown because you need to set dataSource to your TableView Object like self.tableView.dataSource = self. After this you can use freely all methods for UITableView including numberOfSections as you mentioned.

Related

Fix giant viewcontroller with lots of states

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.

Add collectionView to Header

I'm trying to add a collectionView to my CollectionView header. A collectionView inside a collectionView I guess. I've got the header setup and I get a blank collectionView in the header part when I run the app but where can I programme this collectionView.
I've got an outlet for it created in the header.swift file which I can access in my main collectionView file but I can't configure the cells, set the number of sections etc. If it was just a label in the header I could set the text etc here but I'm not sure how to configure a collectionView here.
I tried creating a CollectionViewController file and just linking that to the colectionView in the header but that doesn't work. How can I create a subclass for that collectionView (in the header)?
Swift 3
Okay heres the deal: I guess you use a UICollectionViewController or a UIViewController with a UICollectionView which implements the UICollectionViewDataSource protocol, right? This will massively and unnecessarily bloat your UIViewController.
A better way would be to create a separate object to implment the DataSource of your collection views. One for your main collection view and one for the header collection view. Then you just have to wire them up. You must keep a reference to your data source objects somewhere.
So usually, in viewDidLoad of your view controller you get your collection view and call collectionView.delegate = theDataSourceObject.
theDataSourceObject could be a lazy var in your UIViewController lazy var myDataSourceObject = MyDataSource()
Then, wherever you create your header collection view, you also set its datasource. I hope you understand what I mean and this answer helps you. If you should learn one thing from it than that your view controllers don't necessarily have to be the datasource and/or the delegate of your UITableView or UICollectionView.
They can be totally different objects. A singleton would be an option as well as storing instance variables of your datasource.

How to differentiate iOS UIKit dataSource and delegate methods for multiple objects in the same UIViewController?

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.

UICollectionView: Do I need to use an UICollectionViewController?

I am using XCode5 and iOS7.
Is it possible to embed a UICollectionView into a normal UIViewController class and have the UIViewController implement the methods?
Or do I need the UICollectionViewController?
Which methods are required at minimum?
Yes it is possible to implement UICollectionView without UICollectionViewController. CollectionViews are just like tableView.
As you probably already know, when you use a UITableView you have to set a data source and a delegate in order to provide the data to display and handle events (like row selection).
Similarly, when you use a UICollectionView you have to set a data source and a delegate as well. Their roles are the following:
1. The data source (UICollectionViewDataSource) returns information about the number of items in the collection view and their views.
2. The delegate (UICollectionViewDelegate) is notified when events happen such as cells being selected, highlighted, or removed.
And new to UICollectionView, you have a third protocol you must implement – a protocol specific to the layout manager you are using for the collection view.
You can use a UICollectionView, you'll need the UICollectionView to conform to the UICollectionViewDelegate and UICollectionViewDataSource protocols.
so you will need at a minimum;
numberOfSectionsInCollectionView, numberOfItemsInSection and you'll need to implement cellForItemAtIndexPath to create the cells. Obviously you'll also need to define the Cell
Answer is NO. UICollectionView is subclass of UIVIew and can be added to any view you wish.
Since UIVIewController has view property you can add UICollectionView to it using:
[self.view addSubview:self.collectionView];
Here is a great tutorial with sample project where you can see how to implement UICollectionView in your custom UIViewController subclass:
http://www.raywenderlich.com/22324/beginning-uicollectionview-in-ios-6-part-12
You don't need an UICollectionViewController. Just make sure, that your ViewController implements the UICollectionViewDelegate and UICollectionViewDataSource.
This example should help you with the topic UICollectionView:
http://adoptioncurve.net/archives/2012/09/a-simple-uicollectionview-tutorial/

UICollectionViewCells and Buttons

I've been trying to get my UICollectionView to respond differently to single and double taps but all the answers I have found seem to suggest this is not really feasible because the single taps get recognised first. It works on really slow taps, but anything faster always initiates the default gesture recogniser (if anybody has got this to work I would love to know)...
So anyway, I have now resorted to putting buttons in my UICollectionViewCell (which has it's own class and NIB file).
The question is this:
What is considered the best way to use the button in the UIViewController of the collectionView?
I currently have a protocol in the header of my subclass of UICollectionViewCell and have declared my viewController as the delegate and implemented the required protocol functions.
In collectionView:cellForItemAtIndexPath: I set the VC as the delegate of the cell.
It all works but it seems a bit long-winded, and maybe not a great way of doing this.
The other way I was thinking of was instead of using delegates to simply call addTarget:Action: on the property of the UICollectionViewCell in collectionView:cellForItemAtIndexPath:.
This seems simpler but the delegate pattern looks to me like the better fit.
Any and all advice on which would be better, why, and any more appropriate alternatives welcomed!
Thanks.
You're doing the right think using the delegation pattern. The ultimate responsible object for any action of your views is the viewController who's displaying those views. Therefore, using it as the delegate for you cell's protocol is just right.
create a custom subview of UICollectionViewCell and place your button in the initWithFrame method. Declare the button to be public so you can use it later in your uicollectionviewcontroller or uicollectionview if creating programmatically.

Resources