Swift 3 UITableView Problems - ios

My interface consists of two things inside my main ViewController: a label (the top half of the screen), and a table (the bottom half).
For the life of me, I cannot find a tutorial or example in Swift 3 + iOS 10 where a UITableView is successfully used, as opposed to a UITableViewController which takes up the entire screen.
What must be done to use a UITableView with dynamic cells in the bottom half of your interface?
I tried adding the UITableView, then creating a subclass of UITableViewController, but I was unable to select this in the UITableView's Custom Class -> Class dropdown. Apparently, I need to subclass UITableView, but I can find no examples of how to do this.

Use a standard UIViewController and drag a table view into the canvas.
In IB connect the table view to the IBOutlet and delegate and datasource to the controller.
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView : UITableView!
...
Unlike UITableViewController you have to implement all relevant datasource and delegate methods.

At first , the UITableView and UITableViewController are not the same thing, the TableView is a view and TableViewController is a Controller withe a tableview inside.
If you are using UITableViewController you should drag a UITableViewController, and then change its class in the third tab on the top!
If you are using a basic ViewController and drag a TableView inside, you could get The TableView in the ViewController using an IBOutlet.#John D.
You can use normal ViewController and init a UITableView in the viewDidLoad and add it to the ViewController.
var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView = UITableView.init(frame: CGRect(x:0, y: 300, height: 300, width:screenWidth))
self.view.addSubview(tableView)
self.tableView.register(UINib.init(nibName: "NameListTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: nameListTableViewCellId)
// Do any additional setup after loading the view.
}
set the tableview.delegate = self and tableview.datasource = self,
using methods in the pic and lots other in the UITableViewDelegate and UITabelViewDataSource protocol to Custom your tableView!
hope this would help

Related

Using a UIView xib as a Table View Cell

I have a xib that is a UIView, with class MyUIView. I'd like to re-use this view as a Table View Cell, but I'm not sure how I would do that.
I know I have to register the xib for my table view, like:
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "MyUIView", bundle: nil), forCellReuseIdentifier: "MyUIView")
}
But other than that, I'm not not sure how to upcast it to a Table View Cell. What modifications do I need to make to the regular Table View/Table View Cell process to use my UIView xib as the cell?
Add a UIView control to your table view cell. Then set its class to MyUIView.

Setting up a ViewController for a .xib view

I am neither an iOS developer, nor a swift developer, but please bear with me:
I am currently trying to implement a simple iOS app but I have difficulties understanding how exactly I am supposed to set up custom UIViews and ViewControllers for those UIViews.
I am using a UIScrollView that is containing items a little bit more complex than just images, thats what I use custom views for.
What I did was:
I created a .xib file, the view itself. I added some elements (here it is only a textfield, for simplicity's sake).
I created a cocoa touch class "CustomView" that inherits from UIView and set my view up to be of that class (inside the class I just set up elements and such).
Now I want a ViewController that controls the class whenever it is rendered (for example reacting to the changing textField).
I cant manage everything from my main ViewController, because it would get too big (e.g. 3 scrollViews * 5 subviews that need to be managed).
I want a solution that uses ViewControllers for each subview (in case they themselves will have subviews, too).
How do I do that?
Do I need to add some sort of childViewController?
I really am at loss, most of the blog posts and SO examples simply do not work and/or are outdated and I am unsure about whether or not I got the whole View - ViewController pattern wrong.
Let's say you have two view controllers, MainViewController and TableViewController. TableVC's main view is to be a subview of MainVC's main view. In addition, you wish to pass back to MainVC which cell was selected in TableVC.
A solution is (a) make TableVC be a child to MainVC and (b) make MainVC be a delegate for TableVC.
TableViewController:
protocol TableVCDelegate {
func cellSelected(sender: TableViewController)
}
class TableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// please note that you can do delegation differently,
// this way results in crashes if delegate is nil!
var delegate:TableVCDelegate! = nil
var someValue = ""
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// set someValue to contents in the selected cell or it's data source
someValue = "Hello World!"
delegate.cellSelected(sender: self)
}
}
MainViewController:
class MainViewController: UIViewController, TableVCDelegate {
let tableVC = TableViewController()
override func viewDidLoad() {
// make tableVC be a child of this VC
addChild(tableVC)
tableVC.didMove(toParent: self)
tableVC.delegate = self
// position tableVC.view
tableVC.view.translatesAutoresizingMaskIntoConstraints = false
}
func cellSelected(sender: TableViewController) {
print(sender.someValue) // this should send "Hello World!" to the console
}
}
This is obviously untested code, but it is based on product code. This is meant to be a shell to help you get started.

Using UITableViewController logics in UITableViewDataSource class

I'm doing a refactor because my UITableViewController is bloating very badly. The first thing I'm trying to do is refactoring the data source out of the table view controller like this:
// In my UITableViewController
let ds = MyDataSource()
func viewDidLoad() {
tableView.dataSource = ds
}
In my data source class, I want to use some logic that I feel should belong in the table view controller.
class MyDataSource: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
// I want to use the variable showMore here
return showMore ? 2 : 1
}
// More data source doe
}
The variable showMore is a boolean variable defined in my table view controller and is updated by a button in the footer view of a section.
Question is then, if showMore belongs in the table view controller, how can I access it from my data source class? If it doesn't belong in the
table view controller, where does it belong and why?
Thanks!
First thought that comes to mind - and I'm just typing, not writing in Xcode...
// footerButtonTap
if let ds = tableView.dataSource as? MyDataSource {
ds.showMore = !ds.showMore
tableView.reloadData()
}
Or something along those lines might fit your needs.
UITableViewController is Apple's convenient implementation of a UIViewController that contains a tableView instead of a view, as well as conforming immediately to UITableViewDataSource and UITableViewDelegate. I'd recommend you just use a UIViewController and add a tableView, and then proceed as you have by setting the table's delegate and datasource to MyCustomTableController, which would conform to both UITableViewDataSource and UITableViewDelegate. All logic should be handled inside the controller.

Switching between UITableViewController and UIViewController with table view inside

I am trying to transition from a UITableViewController to a UIViewController with a UITableView within it.
In my HomeViewController, I changed it from
HomeViewController: UITableViewController
to
HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
Now in storyboard, when I drag a Table View onto the View Controller, the TableView automatically resizes to the full screen... I made a reference to tableView in the Controller and set
tableView.delegate = self
tableView.datasource = self
but in HomeViewController when I print (self.view is UITableView) it prints true. When I tried to delete the TableView from the HomeVC in storyboard, and add a UIView instead, it wouldnt let me. I am confused why? How can I transition from TableView to TableView within UIViewController. Thanks!
UITableViewController is a subclass of UIViewController, in your strorybord you have built in UITableViewController that Manages a UITableView and its custom class should a subclass of UITableViewController. so the change you made to you custom class to a subclass of UIViewController will not work as you expected.
You need to drag a UIViewController then add UITableView as any view. then set custom class the one you have.
Also: .h
#interface HomeViewController : UIViewController
//...
#end
.m
#interface HomeViewController ()<UITableViewDataSource,UITableViewDelegate> //implement Protocol
//...
#end

UICollectionView wrapped in a UIViewController

I have a UICollectionView that I placed in a custom UIViewController via Storyboard and pinned its leading/trailing/top/bottom space to its superview.
Then I have a custom UICollectionViewController subclass that should use the collection view. So in the superview's UIViewController (PrimaryViewController) I have an outlet to the collection view and I instantiate my custom UICollectionViewController. I assign it the collection view and I assign the custom UICollectionViewController as delegate and dataSource for the collection view.
But when I run this, the collection view doesn't appear on the screen. It is obvious that the viewDidLoad() doesn't get called in the custom UICollectionViewController class so either I'm missing a key part or I'm approaching this the wrong way.
Can somebody tell me how to construct the connection between the collection view (which is placed via Storyboard) and the custom UICollectionViewController class (which is code only) in a way that makes this work properly?
Here's my (simplified) code so far ...
class PrimaryViewController : UIViewController {
#IBOutlet private weak var _collectionView:UICollectionView!
private var _collectionViewCtrl:CustomCollectionViewController!
override func viewDidLoad() {
super.viewDidLoad()
_collectionViewCtrl = CustomCollectionViewController(collectionView: _collectionView)
}
}
class CustomCollectionViewController : UICollectionViewController {
init(collectionView:UICollectionView) {
super.init(nibName: nil, bundle: nil)
self.collectionView = collectionView
self.collectionView.delegate = self
self.collectionView.dataSource = self
}
required init(coder aDecoder:NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
In IB or your Storyboard, you can use a container view and embed your custom collection view controller inside. This gives you the ability to manipulate each view controller in it's own context, because they each have their own nib, and will handle instantiating your collection view controller auto-magically.
Your PrimaryViewController can look like this:
class PrimaryViewController : UIViewController {
#IBOutlet private weak _collectionView: UIView
private var _collectionViewController: CustomCollectionViewController! {
// ???: You can also iterate through child view controllers looking for a class match if you embed other controllers.
return self.childViewControllers[0] as CustomCollectionViewController!
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Which will also call viewDidLoad() on your CustomCollectionViewController. You can hide and show the view through the _collectionView property, or directly manipulate it through _collectionViewController.
The pain comes from any logic that may be the appearance logic (viewWillAppear(_: Bool), viewWillDisappear(_: Bool), etc) because you'll have to trigger those yourself.
Your storyboard should look something like this (My container view is hidden):
Note that the object that acts as the delegate/datasource for a UICollectionView does not have to be derived from UICollectionViewController. In fact, it shouldn't be unless you dragged out a UICollectionViewController in storyboard.
The datasource/delegate class should be derived from NSObject
#interface CustomCollectionViewSupervisor : NSObject <UICollectionViewDataSource, UICollectionViewDelegate>
and must implement the datasource/delegate methods, including but not necessarily limited to
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

Resources