This question already has answers here:
TableViewCell is not clickable with one finger tap, but it is with two fingers
(3 answers)
Closed 3 years ago.
I'm not receiving the touches. It shows the selection on the iPhone's screen, but it doesn't performs the method didSelectRow.
usersTV.register(UserCell.self, forCellReuseIdentifier: "userCell")
usersTV.dataSource = self
usersTV.delegate = self
usersTV.backgroundColor = .clear
usersTV.separatorColor = .white
usersTV.translatesAutoresizingMaskIntoConstraints = false
usersTV.isHidden = true
usersTV.tableFooterView = UIView()
usersTV.isUserInteractionEnabled = true
usersTV.isEditing = false
usersTV.allowsSelection = true
usersTV.allowsSelectionDuringEditing = false
usersTV.allowsMultipleSelection = false
usersTV.allowsMultipleSelectionDuringEditing = false
usersTV.delaysContentTouches = false
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
Everything is programatically written.
The cells are custom with 3 labels and added constraints.
What could be the problem ?
UPDATE:
class UserCell : UITableViewCell{
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
let viewsDict = ["userName":userName,"field1":field1,"field2":field2]
contentView.superview?.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[userName(120)]-8-[field1]-8-[field2(120)]-8-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDict))
contentView.superview?.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[userName]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDict))
contentView.superview?.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[field1]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDict))
contentView.superview?.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[field2]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDict))
UPDATE:
The didSelectRow method works only if you tap with 2 fingers...
TableViewCell is not clickable with one finger tap, but it is with two fingers
The answer of this question helped me. I've set GestureRecognizer on the main view. When I remove it the problem fixes.
I think this code will help you.If not,There may be a issue with the label constraints.
#IBOutlet weak var UserTV: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
UserTV.register(UserCell.self, forCellReuseIdentifier: "userCell")
UserTV.dataSource = self
UserTV.delegate = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let vc :UserCell = self.UserTV.dequeueReusableCell(withIdentifier: "userCell") as! UserCell
vc.textLabel?.text = "Index: \(indexPath.row)"
vc.backgroundColor = UIColor.red
return vc
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Slected \(indexPath.row)")
}
First of all, here is my comment on your code:
No need to go much complex for this easy task.
Don't forgot to set delegate and datasource properly.
No need to use Visual Format way to set constraints, use Anchors.
My suggestion for you:
Always try to use UICollectionView instead of UITableView.
class SampleTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// MARK: - Variables
lazy private var listTableView: UITableView = {
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.delegate = self
tableView.dataSource = self
return tableView
}()
// MARK: - View LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
initialSetup()
}
// MARK: - Private Methods
private func initialSetup() {
view.backgroundColor = .white
view.addSubview(listTableView)
listTableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
listTableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
listTableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
listTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
listTableView.register(UITableViewCell.self, forCellReuseIdentifier: "listCell")
}
// MARK: - TableView Methods
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "listCell", for: indexPath)
cell.textLabel?.text = "Table Row - \(indexPath.row)"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(#function)
}
Related
I am setting up tableview programmatically, I am constructing a setting page with sections, but for some reason my cells loads on the same row, maybe there is something easy I am missing, I need help to fix this problem here is a snapshot for what I am getting.
My intent to create a static custom cells, I had initially structured custom cells to load without the dequeueReusableCell use, but it loaded the cells again on the same row, I tried using array of cells configure each row with switch cases and had the similar result, and I ended up going with very simple array of strings and configure cells within cellForRowAt but also it didn't work.
import UIKit
class SettingsVC: UIViewController, StoryboardCoordinator , UITableViewDataSource, UITableViewDelegate {
//MARK: - Variables
var tableView = UITableView()
weak var coordinator: MainCoordinator?
let settings = ["Password Lock", "Unlock With TouchID", "Access Your Location?"]
//MARK: - TableView UI configuration
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return settings.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SettingsRow
cell.switchView.rowTitle.text = settings[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
override func viewDidLoad() {
super.viewDidLoad()
setup()
tableView.delegate = self
tableView.dataSource = self
tableView.register(SettingsRow.self, forCellReuseIdentifier: "cell")
tableView.allowsSelection = false
tableView.translatesAutoresizingMaskIntoConstraints = false
}
func setup() {
view.addSubview(tableView)
addConstraints()
}
func addConstraints(){
NSLayoutConstraint.activate([
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),])
}
}
I have collapse and expand animation in UITableView. Tableview has two section in which first section data is collapse and expand. This thing perfectly working with ios 10 but in ios 11 Section view repeated or overlapped with cell data which is expanded.
Below is my code
//MARK: -Table View delegate Method
func numberOfSections(in tableView: UITableView) -> Int {
return read_Localizable("titleHelpSection").components(separatedBy: ",").count
}
//MARK: -Table View Datasource Method
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat{
return 44.0
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
var headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "headerView")
let arrSection = read_Localizable("titleHelpSection").components(separatedBy: ",")
if headerView == nil
{
headerView = UITableViewHeaderFooterView(reuseIdentifier: "headerView")
headerView?.contentView.backgroundColor = UIColor.white
let lblResult = UILabel()
lblResult.tag = 123456
lblResult.font = AppCommonSNMediumFont()
lblResult.textColor = UIColor.black
lblResult.translatesAutoresizingMaskIntoConstraints = false
headerView?.contentView.addSubview(lblResult)
let seperator = UIView()
seperator.translatesAutoresizingMaskIntoConstraints = false
seperator.backgroundColor = UIColor.black
headerView?.contentView.addSubview(seperator)
headerView?.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[seperator]|", options: [], metrics: nil, views: ["seperator":seperator]))
headerView?.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[lable]-(>=8)-|", options: [], metrics: nil, views: ["lable":lblResult]))
headerView?.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[lable]-[seperator(1)]|", options: [], metrics: nil, views: ["lable":lblResult,"seperator":seperator]))
}
if let lblResult = headerView?.contentView.viewWithTag(123456) as? UILabel
{
lblResult.text = arrSection[section]
}
return headerView
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 20.0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0
{
return (arrHelpData.count)
}
else
{
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0
{
var cell = tableView.dequeueReusableCell(withIdentifier: "HelpCell") as? CellHelp;
if cell == nil {
cell = CellHelp(style: .default, reuseIdentifier: "HelpCell")
cell?.selectionStyle = .none
cell?.txtContain.delegate = self
}
if let objModel = arrHelpData.object(at: indexPath.row) as? HelpModel
{
cell?.lblTitle.text = objModel.helpTitle
if objModel.isExpanded == true
{
cell?.txtContain.text = objModel.helpDesc
}
else
{
cell?.txtContain.text = ""
}
cell?.imgArrow.isHighlighted = !objModel.isExpanded
}
return cell!
}
else
{
var cell = tableView.dequeueReusableCell(withIdentifier: "DefultCell")
if cell == nil
{
cell = UITableViewCell(style: .default, reuseIdentifier: "DefultCell")
cell?.textLabel?.textColor = color1F87A3()
cell?.textLabel?.font = AppCommonSNRegularFont()
cell?.selectionStyle = .none
cell?.textLabel?.numberOfLines = 0
}
cell?.textLabel?.text = read_Localizable("titleSettings")
return cell!
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 && indexPath.row < (arrHelpData.count)
{
if let objModel = arrHelpData.object(at: indexPath.row) as? HelpModel
{
if objModel.isExpanded == true
{
objModel.isExpanded = false
}
else
{
objModel.isExpanded = true
}
tableView.reloadData()
}
}
}
Actual view
Section overlapped on cell data
This is very frustrating iOS11 issue, something to do around estimatedHeight issue, If you really want to keep the self sized row and header then u need to go with the below approach.
Declare variable which holds the height of the cell/header and store height into that and used it as below:
var cellHeightDictionary: NSMutableDictionary // To overcome the issue of iOS11.2
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 125
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeightDictionary.setObject(cell.frame.size.height, forKey: indexPath as NSCopying)
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if cellHeightDictionary.object(forKey: indexPath) != nil {
let height = cellHeightDictionary.object(forKey: indexPath) as! CGFloat
return height
}
return UITableViewAutomaticDimension
}
This is the only solution which worked for me for iOS11 issues with auto sizing cells. Otherwise people suggest to keep estimatedHeight 0 to get rid off such issues.
In your case first try doing this for cell and that doesn't solve the issue completely then do same for header height also. Hope this helps!
Don't forget to test in both iOS11.1 and iOS11.2.
So I want to change the default animation duration of UITableView's beginUpdates() & endUpdates(), which I think is 0.3s.
I tried placing them inside a UIView animation block, then I got abrupt animation.
To see what I am talking about, create a new iOS "Single View Application" Project, and replace ViewController.swift with the following code:
class ViewController: UIViewController {
var tableView = UITableView()
var isExpanded = false
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
tableView.frame = view.bounds
tableView.dataSource = self
tableView.delegate = self
let changeHeightButton = UIBarButtonItem(title: "Change Height", style: .plain, target: self, action: #selector(changeHeight))
navigationItem.rightBarButtonItem = changeHeightButton
}
func changeHeight() {
isExpanded = !isExpanded
UIView.animate(withDuration: 0.5, animations: {
self.tableView.beginUpdates()
self.tableView.endUpdates()
}, completion: nil)
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = "Section \(indexPath.section), Row \(indexPath.row)"
return cell
}
func numberOfSections(in tableView: UITableView) -> Int{
return 4
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Section: \(String(section))"
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if isExpanded && indexPath == IndexPath(row: 0, section: 0) { return 300 }
else { return 44 }
}
}
i am trying to add a TableView inside UICollectionViewCell, so i want to manage that cell by myself from TableView.
So to be more clear, if indexPath.row is 2, then i want to call my tableView cell's inside collectionview indexPath.row.
Please check the picture, i have made with red colour what i want to do.
I created everything programmatically, using UICollectionViewController and UICollectionViewControllerFlowLayout.
For those who need it, i found the solution:
class CustomizedCell: UICollectionViewCell, UITableViewDataSource, UITableViewDelegate {
var tableView = UITableView()
let cellIdentifier: String = "tableCell"
override func layoutSubviews() {
super.layoutSubviews()
tableView.delegate = self
tableView.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: cellIdentifier)
cell.textLabel?.text = "1 CUP"
cell.detailTextLabel?.text = "Whole"
return cell
}
}
Then at viewDidLoad method at CollectionView i did this:
collectionView?.register(CustomizedCell.self, forCellWithReuseIdentifier: "cell")
And after that i have called like this at cellForRowAt indexPath method of UICollectionView:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CustomizedCell
return cell
}
You can create a custom UICollectionView cell for that indexpath. And add a tableview in the cell xib.
Implement the delegate methods of tableview in custom cell class.
class CustomCollectionViewCell: UICollectionViewCell, UITableViewDataSource, UITableViewDelegate
{
#IBOutlet var tableView: UITableView!
override func layoutSubviews()
{
super.layoutSubviews()
tableView.delegate = self
tableView.dataSource = self
}
}
The approaches above don't work well in with the MVC pattern. I recommend creating an NSObject subclass which conforms to UITableViewDelegate and UITableViewDataSource.
For example:
class DataProvider: NSObject, UITableViewDelegate, UITableViewDataSource {
let dataManager = DataManager()
let reuseId = "Cell"
//MARK: - DataSource Methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataManager.data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseId, for: indexPath)
cell.backgroundColor = .yellow
return cell
}
//MARK: - Delegate Methods
}
Now in your UICollectionViewCell subclass you can specify the tableView data source and delegate properties, like so:
class ContainerCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var collectionView: UICollectionView!
let dataProvider = DataProvider()
let tableView: UITableView = {
let table = UITableView()
table.translatesAutoresizingMaskIntoConstraints = false
return table
}()
override func awakeFromNib() {
super.awakeFromNib()
addSubview(tableView)
tableView.fillSuperview()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: dataProvider.reuseId)
tableView.delegate = dataProvider
tableView.dataSource = dataProvider
}
}
Perhaps not perfect, but achieves better encapsulation than the above answers.
I found a solution that's working for me.
import UIKit
class FirstCollectionViewCell: UICollectionViewCell {
let cellId = "cellId"
let tableView:UITableView = {
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
return tableView
}()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .blue
addSubview(tableView)
setUpViews()
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":tableView]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":tableView]))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init is not done")
}
func setUpViews() {
tableView.delegate = self
tableView.dataSource = self
tableView.register(MyCell.self, forCellReuseIdentifier: cellId)
}
}
extension FirstCollectionViewCell: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! MyCell
cell.label.text = "Testing testing"
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 40.0
}
}
class MyCell:UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUpViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// creating a label to display some dummy text
let label:UILabel = {
let label = UILabel()
label.text = "test"
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
func setUpViews() {
addSubview(label)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":label]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":label]))
}
}
I'm creating an iOS app using swift. I want to build a non scrollable tableView which shows on screen all informations contained in datasource, so the height of each cell depends on the number of entries in data. For example, if the height of the view is 500 and data.count = 10, each cell's height is 50. A problem appears when the cell's height is ~100.8 (corresponding to 5 entries in my data, using my iPhone 5). In fact, even by setting tableView.separatorStyle = .None , a weird separator appears for this cell's height.
Below, the first image (7 entries in data) is normal and on the second (5 entries in data) those separators appear.
Here is my view controller :
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
let reuseIdentifier = "Cell"
var data = ["bobby", "bob", "john", "helena", "clara", "oliver", "steve"]
var visibleHeight:CGFloat!
override func viewDidLoad() {
super.viewDidLoad()
edgesForExtendedLayout = .None
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: reuseIdentifier)
editModeOff()
tableView.scrollEnabled = false
visibleHeight = viewVisibleSize.height
tableView.separatorStyle = .None
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath)
cell.textLabel!.text = data[indexPath.row]
cell.selectionStyle = .None
return cell
}
func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {
let stringToMove = data[sourceIndexPath.row]
data.removeAtIndex(sourceIndexPath.row)
data.insert(stringToMove, atIndex: destinationIndexPath.row)
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete{
data.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade)
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
print(visibleHeight/CGFloat(data.count))
return visibleHeight/CGFloat(data.count)
}
func editModeOn(){
tableView.setEditing(true, animated: true)
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "editModeOff")
}
func editModeOff(){
tableView.setEditing(false, animated: true)
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Edit, target: self, action: "editModeOn")
}
}
extension ViewController{
var viewVisibleSize:CGSize{
var size = view.bounds.size
if !UIApplication.sharedApplication().statusBarHidden{
size.height -= UIApplication.sharedApplication().statusBarFrame.height
}
if let navigationController = navigationController{
size.height -= navigationController.navigationBar.bounds.height
}
if let tabBarController = tabBarController{
size.height -= tabBarController.tabBar.bounds.height
}
return size
}
}
I always clear the color of the separator:
tableView.separatorColor = UIColor.clearColor()
I have found a dirty solution by setting :
cell.contentView.layer.borderWidth = 0.5
cell.contentView.layer.borderColor = UIColor.whiteColor().CGColor
in tableView:cellForRowAtIndexPath: method. But for sure, there is a better way...
In your viewDidLoad: you can try self.tableView.tableFooterView = UIView()
It is funny. Problem in your function tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
It has strange behavior for some float numbers and a separator will appear.
I offer you round a returning height like this:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
print(self.visibleHeight/CGFloat(self.tableArray.count))
let rett = self.visibleHeight/CGFloat(self.tableArray.count)
let convert = NSString(format: "%.0f", rett)
return CGFloat(convert.floatValue)
}