Why can I not assign dataSource directly? - swift

I would like to understand why to following Swift code does not work, but using the commented version does. I'm not sure if dataSources are typically wrapped into a separate class, but I don't think that should matter. I'm using Xcode 6.3.2, all up to date.
// MainViewController.swift
import UIKit
class MainViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var dataSource:UITableViewDataSource?
override func viewDidLoad() {
super.viewDidLoad()
// dataSource = MainTableViewDataSource()
// tableView.dataSource = dataSource
tableView.dataSource = MainTableViewDataSource()
}
}
The MainTableViewDataSource is just a class which implements the UITableViewDataSource protocol and uses some dummy data.
// MainTableViewDataSource.swift
import UIKit
class MainTableViewDataSource : NSObject, UITableViewDataSource {
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 100
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1000
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return String(section + 1)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell()
cell.textLabel?.text = "Joejoe"
return cell
}
}

According to Apple's documentation https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/#//apple_ref/occ/instp/UITableView/dataSource
dataSource property of UITableView is unowned in Swift which is (assign) for Objective-C meaning that this property does not increase the reference count. So right after viewDidLoad function, when reference count of your MainTableViewDataSource becomes zero, it gets deallocated.
I recommend reading: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
You'll run into strange outcomes--sometimes even inconsistent--if you don't do the memory management right.

Related

TableViewCell does not get data in Swift

I am using a Custom TableViewCell in TableViewController.
Even the data is getting populated but my TableViewCell does not display it.
Here is my Custom TableViewCell Code
class PlaceItemCellCustom: UITableViewCell {
#IBOutlet weak var placeFace: UILabel?
#IBOutlet weak var placeName: UILabel?
override func awakeFromNib() {
super.awakeFromNib()
}
}
Here is my TableViewContoller
class PlaceListViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
loadListFromSource()
}
// Other code
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return places.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let place = places[indexPath.row]
// I am getting the data
print(place.placeName?.description ?? " " )
let customCell = tableView.dequeueReusableCell(withIdentifier: "PlaceListIdentifier", for: indexPath) as! PlaceItemCellCustom
customCell.placeName?.text = place.placeName
return customCell
}
}
What am I missing here? I am new to IOS app development.
Found similar questions but did not help
Edit: It was working fine for the default TableViewCell.
But when I changed it to custom TableViewCell it does not work. I have set the class name in the storyboard as well.
Here is my Storyboard
Here is the output
As much as I can understand you must have forgotten to connect the IBOutlet of placeName in PlaceItemCellCustom:
In your PlaceItemCellCustom keep placeName as :
#IBOutlet weak var placeName: UILabel!
and in cellForRowAt:
customCell.placeName.text = place.placeName
in this way if you forgot to connect segue Xcode will throw error as :
Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
You can read more about it here :
https://cocoacasts.com/should-outlets-be-optionals-or-implicitly-unwrapped-optionals
You need using this method for get data.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return places.count
}

How to fix 'tableview cellforrowat not called?'

I'm setting up a tableview with customtableview cell, but when i run the app, the data is not shown.
I already check all the connection, identifier, class name, etc
import UIKit
class ViewController: UITableViewController {
#IBOutlet var testingTableView: UITableView!
var data = ["Indomie","Kacang Tanah","Soya"]
override func viewDidLoad() {
super.viewDidLoad()
testingTableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "customCell")
// Do any additional setup after loading the view.
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = testingTableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! customTableViewCell
cell.customLabel.text = data[indexPath.row]
return cell
}
override func numberOfSections(in tableView: UITableView) -> Int {
return data.count
}
}
This is my code for the table view, it's should call the cellforrowat but it's not
You are missing tableView(_:numberOfRowsInSection:) implementation.
You have number of data.count section, but each section has 0 row.
Try replacing numberOfSections(in:) to tableView(_:numberOfRowsInSection:)
I guess you need additional code as below-
testingTableView.delegate = self
testingTableView.datasource = self
testingTableView.reloadData() // I think you missed it!
1). Add this line
#IBOutlet var testingTableView: UITableView! {
didSet {
testingTableView.delegate = self
testingTableView.dataSource = self
}
}
2). You also can add this feature via Stroyboard. Click on your table and using right click drag the pointer on ViewController and add delegate and dataSource.
And i think you missed
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0 //As per your need.
}
You are using the wrong API, numberOfSections returns the number of sections but you have to return the number of rows
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { {
return data.count
}
There is no need to override numberOfRowsInSection, the default value is 1.
And delete
#IBOutlet var testingTableView: UITableView!
There is an implicit tableView property of UITableViewController

Not able to display anything on table view Swift

This is my history view, I have a tableview inside view controller. But for some reason i can't output anything, I am trying to hardcode it and its not displaying anything at all. One thing i know is i need to make tableView functions override and if i do that i get error.
import UIKit
class History: UIViewController, UITableViewDataSource, UITableViewDelegate
{
#IBOutlet var tableView: UITableView!
override func viewDidLoad()
{
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.view.backgroundColor = UIColor(patternImage: UIImage(named: "newBackground.jpg")!)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("historyCell", forIndexPath: indexPath) as! historyCell
cell.durationLabel.text = "98"
return cell
}
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
}
}
heres my class for the cell prototype, and i made sure that the identifier is also "historyCell"
public class historyCell: UITableViewCell{
#IBOutlet var durationLabel: UILabel!
#IBOutlet var kicksLabel: UILabel!
}
How did you connect your prototype cell's controls to the IBOutlets in you historyCell class ? I didn't know that was possible when you're not using a UITableviewController. I've been using tags all this time.
Unless there's something new that I wasn't aware of, your assignment to cell.durationLabel.text should cause unwrapping of a nil (is that the error you're getting ?)

Dynamic datasource/delegates for UITableView in swift

I need to set up different objects based on certain conditions as the datasource & delegate for table view.
But I am not able to assign tableview's datasource/delegate as it throws some errors.
Cannot assign a value of type NSObject? to a value of type UITableViewDelegate?
I did check this Q&A but this did not work.
var dataSourceDelegate:NSObject?
class RootViewController: UIViewController {
...
override func viewDidLoad() {
dataSourceDelegate = TableDataSourceDelegate()
// Table View
tableView = UITableView()
tableView!.setTranslatesAutoresizingMaskIntoConstraints(false)
tableView!.dataSource = dataSourceDelegate
// Cannot assign a value of type NSObject? to a value of type UITableViewDataSource?
tableView!.delegate = dataSourceDelegate
// Cannot assign a value of type NSObject? to a value of type UITableViewDelegate?
view.addSubview(tableView!)
// Constraints
var views:[String:UIView] = ["table":tableView!]
var hTableConstraint = "H:|[table]|"
var vConstraint = "V:|[table]|"
view.addConstraintsToView([hTableConstraint, vConstraint], view: view, viewVariables: views)
}
...
}
This is the datasource/delegate class
class TableDataSourceDelegate:NSObject, UITableViewDataSource, UITableViewDelegate {
// MARK: Datasource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return UITableViewCell()
}
// MARK: Delegates
}
NSObject? doesn't conforms to UITableViewDelegate, neither to UITableViewDataSource. You should create your protocol like
protocol GeneralDataSource: UITableViewDataSource, UITableViewDelegate {}
And then all data sources should conform that protocol.
class MyDataSource: NSObject, GeneralDataSource {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return UITableViewCell()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
}
Then you can use it like this
var myDataSource: GeneralDataSource?
override func viewDidLoad() {
super.viewDidLoad()
self.myDataSource = MyDataSource()
self.tableView.delegate = self.myDataSource
}
This is how your TableDataSourceDelegate should look like:
import UIKit
class TableDataSourceDelegate: NSObject {
}
extension TableDataSourceDelegate: UITableViewDataSource {
#objc func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
#objc func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "defaultCell")
cell.textLabel?.text = "test"
return cell
}
}
extension TableDataSourceDelegate: UITableViewDelegate {
// your delegate implementation here
}
And view controller implementation
import UIKit
// The typealias definition
typealias TVDataSourceDelegate = protocol<UITableViewDataSource, UITableViewDelegate>
class ViewController: UIViewController {
var dataSourceDelegate: TVDataSourceDelegate?
var tableView: UITableView?
override func viewDidLoad() {
super.viewDidLoad()
dataSourceDelegate = TableDataSourceDelegate()
// Table View
tableView = UITableView()
tableView!.translatesAutoresizingMaskIntoConstraints = false
tableView!.dataSource = dataSourceDelegate
tableView!.delegate = dataSourceDelegate
view.addSubview(tableView!)
// other code ...
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Although, I would recommend to separate dataSource and delegate objects (e.g. put the delegate protocol conforming code into your view controller's code.

UITableViewDataSource not being invoked in Swift, Xcode 7 beta 2

This is a bizarre one, & I'm quite happy to be told that I've missed something obvious, but I can't see it.
Firstly, the UITableViewDataSource methods are not even showing up in autocomplete, then they're not called at runtime. Weirdly, the UITableViewDelegate methods are working on both counts.
Here's the (cut-down) code -
class PopupTable : NSObject, UITableViewDataSource, UITableViewDelegate
{
private var tableView : UITableView
init(rect: CGRect)
{
tableView = UITableView(frame: rect, style: UITableViewStyle.Plain)
super.init()
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "PopupCell")
tableView.dataSource = self
tableView.delegate = self
}
func show()
{
if let mainWindow = UIApplication.sharedApplication().delegate?.window!
{
mainWindow.addSubview(tableView)
}
}
// MARK: TableView Delegate & DataSource
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return myData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("PopupCell")!
cell.detailTextLabel?.text = "some text"
return cell
}
}
I have no problems getting this to work in a UIViewController, but that's not what I want here.