I've fetched This Data from API - Which is next 7 days weather report. I want to display this as tableview where
Date will be the as Section
The temperature (Min / Max) as row
But If I select the section number like this -
func numberOfSections(in tableView: UITableView) -> Int {
return myList.count // myList is an array of containing the 7 day's data
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
It printing the same row (1st data of the array) in all section. So how can I print separate weather at separate section without splitting my array?
When it comes to section and rows in UITableView, the key is usually 2D arrays.
Try to create a 2D array like this:
myList[sectionItems][rowItems]
Inside this array should look something like this:
myList = [
[date, minTemp, maxtemp],
[date, minTemp, maxtemp],
[date, minTemp, maxtemp],
[date, minTemp, maxtemp]
]
So your UITableViewDelegate and DataSource functions will look like this:
func numberOfSections(in tableView: UITableView) -> Int {
return myList.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myList[section].count
}
Above example will allow you to have 4 sections and each section will have 3 rows.
Then you can print the date on first row and the rest on other rows.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel.text = myList[indexPath.section][indexPath.row]
return cell
}
Related
I have to make a dynamic datasource for a table, that satisfies the criteria:
we do not know exact number of sections
we do not know exact title for header in section
we do not now how many rows it will be in each section each time
To detect number of rows per section I have the following code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let header = tableView.headerView(forSection: section)
return self.servicesData?.filter({ $0.clubName == header?.textLabel?.text }).count ?? 0
}
where servicesData is the object array that is to be filtered by the header title aka clubName. Titles are gathered from the object array.
For some reason I always get nil when try to access the header. So far I tried calling tableView(_:titleForHeaderInSection:) directly in numberOfRowsInSection but obviously with no luck.
Feedback much appreciated.
It is nil because it is not created at that moment. You should not use tableView.headerView(forSection: section) in numberOfRows. You should use the model from where you get the title to use it to filter in the array.
You should fetch all of your data before populating the table view and first. Then you should implement:
func numberOfSections(in tableView: UITableView) -> Int {
return headerModels.count
}
where headerModels it's an array of objects with your title and it's items like:
class HeaderModel {
let title: String
let items: [YourItem]
}
and then:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return headerModels[section].items.count
}
So, as per #shurtugal 's solution it is possible to pass-in an array of objects to populate the table. I thought that creating a utility class for this very case may be too much. So here's the slightly altered way:
Consider a dictionary var servicesData = [String: [CustomObject]]() that is populated each time the ViewController shows up. The dictionary can have indefinite number of keys and indefinite number of values inside each key. Algorithm of populating the dictionary is taken from this answer.
Thereby, UITableViewDatasource methods can be defined like this:
func numberOfSections(in tableView: UITableView) -> Int {
self.servicesData.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Array(self.servicesData.values)[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
/* cell creation code code */
/// sample line
cell?.someLabel.text = Array(self.servicesData.values)[indexPath.section][indexPath.row]
return cell
}
Im a complete beginner to swift and iOS and I'm trying to write some code which will take some json and put it into an array of objects and then use that array to populate the tableview.
The problem is when I try to populate the tableview it just prints the first one so it looks like this:
here is the code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "comicCell", for: indexPath) as! ComicCell
cell.title.text = comics?[indexPath.row].title
cell.dateOnSale.text = comics?[indexPath.row].dateOnSale
return cell
}
I tried to print the array of objects in a simple for loop and it works fine which led me to believe my problem is in the function above
The cellForRowAt method seems OK, I think you're having trouble with the numberOfSections and numberOfRowsInSection methods of tableView, the former must return 1 and the latter must return comics.count in your case.
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comics.count
}
i have the dictionary - dictTime: [Int:[Int]] and I'd like to show it in tableView in cell.
To show key in every cell - not a problem, but I'd like to show every element of value of dictionary in "own" UILabel, so I created [UILabel] and understand that count of UILabel in array must be equal count of elements in value of dictionary, but how to do it in func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell for showing for every row (row - it's key-[value])?
Assuming your dictionary is like [Int1: [Int2]], that means:
dictTime.allKeys will give you array of all Int1
dictTime[Int1] will give you respective [Int2]
Example:
var dictTime = [1: [1,2], 2: [2,3], 3: [3,4]]
For showing these in a tableView:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dictTime.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath)
let keys = Array (dictTime.keys)
cell.textLabel?.text = String (keys[indexPath.row])
cell.detailTextLabel?.text = String (dictTime[indexPath.row])
return cell
}
In func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell call an other function and pass your dictionary value to that function for example [1,2,3] also pass your tbaleviewcell to that function. Now in that function run a loop on your dictionary array [1,2,3] and one by one UILabel into your tableviewcell programmatically.
I am not sure I understand the problem. If you want to have as many rows as dictionary entries, use the following:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dictTime.count
}
If you want to have as many labels in your cell, as entries for each key in your dictionary, you need to implement a complicated solution.
I would suggest creating a "super cell" which has the maximum amount of labels, put them in a stach view, and hide them according to the number of entries.
How to prevent crashes when an array is empty and you make a request from a UITableView or UIPickerView?
My current method is to always initialize my arrays before using them with dummy data but I'm not really happy with this method since sometimes the dummy data is not needed and even-worse, sometimes it doesn't even make sense to show the data, in fact most of the time what I want is to show an empty table if there is no data.
For instance if I will be retrieving an array from NSUserDefaults to be used in a UITableView I usually initialize it in the AppDelegate as follow...
AppDelegate.swift:
NSUserDefaults.standardUserDefaults().registerDefaults([
keyMyAarray:["Dummy Data"]// initializing array
])
SomeViewController:
var myArray = read content from NSUserDefaults...
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
fun tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell()
cell.textLabel.text = myArray[indexPath.row]
return cell
}
Again, how can I safely use an un-initialized array in a UITableView and show an empty table?
There is no need to put "dummy data" in your array. You can just initilize an empty array. like below
var myArray = [String]()
And in numberOfRowsInSection return myArray.count. If count is zero, cellForRowAtIndexPath will not be called and you are safe to go.
3 empty rows by default.
var myArray:Array<String>? = ...
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
fun tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myArray?.count ?? 3
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell()
if let arrayStrings = myArray, arrayStrings.count > indexPath.row {
cell.textLabel.text = arrayStrings[indexPath.row]
}
return cell
}
I'm new to Swift and iOS programming and I'm having a play with making some simple apps. I am trying to build a master-detail app.
In the master view I've given the tableview two sections and I've set the content of the table view to "static cells". Initially I gave each section 3 rows and was able to successfully run the app with the following code in the mainviewcontroller file:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
I am now wanting to have 11 rows in the first section, and 5 rows in the second section but the changes I have tried to the code prevent the app from running. I've tried:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 16
}
and I've tried:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 11
}
but it falls over. What am I doing wrong here?
You should use the section to decide how many rows there should be in that section. For example, you could have a variable in your view controller:
let numberOfRowsAtSection: [Int] = [11, 5]
Now in numberOfRowsForSection:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var rows: Int = 0
if section < numberOfRowsAtSection.count {
rows = numberOfRowsAtSection[section]
}
return rows
}