UITableView programmatically in Swift Empty - ios

I'm making a UITableView in swift programmatically. With the following code (I have UITableViewDelegate and UITableViewDataSource in there):
var tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.frame = CGRectMake(25, 180, 220, 150)
tableView.delegate = self
tableView.delegate = self
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
self.view.addSubview(tableView)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return options.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel?.text = options[indexPath.row]
println("cell label is")
println(cell.textLabel!.text)
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 30
}
The table is coming blank, however. The cells don't show up. Any advice?

Why tableView.delegate initialized twice in viewDidLoad?One of them must be datasource isn't it?
override func viewDidLoad() {
super.viewDidLoad()
tableView.frame = CGRectMake(25, 180, 220, 150)
tableView.delegate = self
tableView.datasource = self
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
self.view.addSubview(tableView)
}

Call tableView.reloadData() after adding it to self.view in viewDidLoad.

Not only you are missing self.tableView.reloadData() . What do you have inside of the data structure options where are you getting the data from?
you said you are Querying from parse :
var query = PFQuery(className: "whatever class name")
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil {
if let newObjects = objects as? [PFObject]{
for one in newObjects {
var message = one["TextMessage"] as! String
// so add this data message data into your array
// then reload Data
}
}
}
else{
print("error")
}
}
}
And also change this
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
To
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return options.count
}

I noticed that you (unconventionally) use each element in options as i row in its own section. But, when you set the label, you base it on the row number, which will alway be zero. What you want is:
cell.textLabel?.text = options[indexPath.section]
As for the table being blank, I would think that either
Your first element is nothing
The array is empty
You are not setting up the sections properly

Related

Custom cell above other cells in UITableView

I have a UITableView that gets its data from a sorted array. [A-Z].
How can I place a default cell to select at the top like this.
If a user doesn't want to click any of the other cells?
Here is my UITableViewCode below.
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.allowsSelection = true
tableView.allowsMultipleSelection = false
let groupedDictionary = Dictionary(grouping: nameArray, by: {String($0.prefix(1))})
// get the keys and sort them
let keys = groupedDictionary.keys.sorted()
// map the sorted keys to a struct
sections = keys.map{ Section(letter: $0, name: groupedDictionary[$0]!.sorted()) }
self.tableView.reloadData()
}
// MARK: - Table view data source
var selectedIndexPath = IndexPath()
override func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].names.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "HomeNames")
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeNames", for: indexPath)
let section = sections[indexPath.section]
if indexPath == selectedIndexPath {
cell.accessoryType = UITableViewCell.AccessoryType.checkmark
} else {
cell.accessoryType = UITableViewCell.AccessoryType.none
}
cell.textLabel?.text = section.names[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let section = sections[indexPath.section]
selectedIndexPath = indexPath
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
tableView.register(UINib(nibName: "BBcell", bundle: nil), forCellReuseIdentifier: "Cell")
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
selectedHomeName = section.name[indexPath.row]
navigationItem.title = (selectedHomeName)
self.dismiss(animated: true, completion: nil)
}
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return sections.map{$0.letter}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section].letter
}
}
The simplest solution, in my opinion, would be to insert a new Section at the beginning of your sections variable after this line.
sections = keys.map{ Section(letter: $0, name: groupedDictionary[$0]!.sorted()) }
Something like:
sections.insert(Section(letter: "Default", ["All makes"]), at: 0)
I could have messed up the syntax a bit as I don't know your Section

reloadData() calls cellForRowAtIndexPath for every cell

So I'm having this issue that when reloadData() is called after the initial API call, it calls willDisplayCell method which when the last cell is displayed will load more data (API returns 10 data at a time).
However in the view it can show only 4 - 5 cells as I set the row height to 175 points manually. Does anyone know why is this happening?
If this is how the tableView works what can I do to make my tableView to load only 10 initially?
Following is my code.
class MainViewController: UIViewController {
var tableView: UITableView!
var photoViewmodel: PhotoViewModel!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Home"
initTableView()
photoViewmodel = PhotoViewModel()
photoViewmodel.loadNewPhotos {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
func initTableView() {
tableView = UITableView.init(frame: self.view.frame, style: .plain)
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = 175
tableView.separatorStyle = .none
tableView.register(HomeTableViewCell.nib, forCellReuseIdentifier: HomeTableViewCell.identifier)
view.addSubview(tableView)
}
}
extension MainViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return photoViewmodel.photos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("cellForRowAt")
let cell = tableView.dequeueReusableCell(withIdentifier: HomeTableViewCell.identifier, for: indexPath) as! HomeTableViewCell
cell.tag = indexPath.row
cell.configureCell(url: photoViewmodel.photos[indexPath.row].regularImgUrl, cacheKey: indexPath.row)
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
print("willDisplay")
let lastCell = photoViewmodel.photos.count - 1
if indexPath.row == lastCell {
print("add 10 more photos")
photoViewmodel.loadNewPhotos(
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
}
}

Data loading issue in Table View in IOS

I have a table view controller in my view controller. When I give it static number of rows and cell for row index method name it shows nothing to me in the table view. I have also reload the table view but it isn't showing I don't know why is it so,
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell (style: .subtitle, reuseIdentifier: "cellID")
let message = messages[indexPath.row]
cell.textLabel?.text = message.text
return cell
}
Recheck if u have set
tableView.delegate = self
tableView.datasource = self
Also put a breakpoint on cellForRowAtIndexpath to check if code runs through the block.
Also Recheck the cellIdentifier (cellID) is correct or not.
class ViewController:UIViewController,UITableViewDataSource,UITableViewDelegate {
//Getting the reference variables of storyboard
#IBOutlet weak var tableView:UITableView!
var messages = [String]()
override func viewDidLoad() {
super.viewDidLoad()
//Add some packages
messages.append("Super")
messages.append("Free ")
messages.append("Miscellaneous")
messages.append("All ")
tableView.datasource = self
tableView.delegate = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell (style: .subtitle, reuseIdentifier: "cellID")
let message = messages[indexPath.row]
cell.textLabel?.text = message.text
return cell
}
}
Use this . This one works for me
class yourViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var tableView:UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.datasource = self
tableView.delegate = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell=tableView.dequeueReusableCell(withIdentifier: "cellID",for : indexPath)
let message = messages[indexPath.row]
cell.textLabel?.text = message.text
return (cell)
}
}

Class implementing UITableViewDataSource is always null

I have a tableview that should have its delegate and datasource properties set from InsertIntoTableViewDelegate and InsertIntoTableViewDatasource Classes respectively. However, my InsertIntoTableViewDatasource class always returns null.
Here is the code:
class InsertIntoTableViewDatasource: NSObject,UITableViewDataSource {
var data:NSMutableArray
init(With data: NSMutableArray){
self.data = data
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("rowCell", forIndexPath: indexPath)
cell.textLabel?.text = data[indexPath.row] as? String
return cell
}
}
Here is the how the tableview is being set:
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Testing"
tableView.dataSource = InsertIntoTableViewDatasource(With: data)
tableView.delegate = InsertIntoTableViewDelegate()
}
Why is this the case?
UITableView does not retain its datasource, so your datasource is getting deallocated as soon as your viewDidLoad function ends.
You need to hold a reference to your datasource as a property in your view controller. Same thing with the delegate.

Dynamic viewForHeaderInSection and multiple cellForRowAtIndexPath

I'm trying to make a custom cell to be the Section of my cells:
For this I'm overriding some functions like:
numberOfRowsInSection
viewForHeaderInSection
heightForHeaderInSection
And I'm working with multiple cellForRowAtIndexPath I'm using a if indexPath.row to identify the Cell and populate them in a dynamic way.
import UIKit
class TesteTableViewController: PFQueryTableViewController {
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
loadCollectionViewData()
}
func loadCollectionViewData() {
// Build a parse query object
let query = PFQuery(className:"Feed")
// Check to see if there is a search term
// Fetch data from the parse platform
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
// The find succeeded now rocess the found objects into the countries array
if error == nil {
print(objects!.count)
// reload our data into the collection view
} else {
// Log details of the failure
}
}
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return objects!.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
var header = tableView.dequeueReusableCellWithIdentifier("Cell2")! as! TesteTableViewCell
return header
}
override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 30.0
}
// Initialise the PFQueryTable tableview
override init(style: UITableViewStyle, className: String!) {
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
// Configure the PFQueryTableView
self.parseClassName = "Feed"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: TesteTableViewCell!
let object = objects![indexPath.section]
if indexPath.row == 0 {
cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TesteTableViewCell
// Extract values from the PFObject to display in the table cell
if let nameEnglish = object["name"] as? String {
cell?.label1?.text = nameEnglish
}
}
else{
cell = tableView.dequeueReusableCellWithIdentifier("Cell2", forIndexPath: indexPath) as! TesteTableViewCell
// Extract values 2from the PFObject to display in the table cell
if let nameEnglish2 = object["brief"] as? String {
cell?.label2?.text = nameEnglish2
}
}
return cell
}
}
With my code I have this result:
I'm successfully populating both Cells with different Identifiers.
But look like this function is called before the cellForRowAtIndexPath and it return the content that I have in the storyBoard and not the content that I'm populating dynamically.
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
var header = tableView.dequeueReusableCellWithIdentifier("Cell2")! as! TesteTableViewCell
return header
}
And I really think that is my problem. (The order that things happen).
Any ideas?
Thanks.
You need to move the code which you have in cellForRowAtIndexPath for row != 0 because that block of code is never executed which is causing static data rendering from storyboard instead of dynamic data.
In this case you have to give dynamic data to cell in viewForHeaderInSection method so that you cell will populate that information on each reload.
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
var header = tableView.dequeueReusableCellWithIdentifier("Cell2")! as! TesteTableViewCell
let object = objects![section]
if let nameEnglish2 = object["brief"] as? String {
header.label2?.text = nameEnglish2
}
return header
}

Resources