I'm trying to make a very simple indexed tableView in Swift 3.
I managed to add the index to the view, but as soon as I added the sections headers, every cell showed a strange separator line on the right side (see screenshot)
I have no idea where it could come from and it doesn't appear in other indexed tableview tutorials I saw online.
This is the code for the TableViewController:
class TableViewController: UITableViewController
{
var tableData : [String] = []
var indexOfNumbers : [String] = []
override func viewDidLoad()
{
super.viewDidLoad()
let numbers = "100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500"
tableData = numbers.components(separatedBy: " ")
let indexes = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
indexOfNumbers = indexes.components(separatedBy: " ")
}
override func numberOfSections(in tableView: UITableView) -> Int { return indexOfNumbers.count }
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 1 }
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = tableData[indexPath.section]
print(indexPath.section, indexPath.row, separator : " ")
return cell
}
override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int
{
let temp = indexOfNumbers as NSArray
return temp.index(of: title)
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
{
return "Section \(section)"
}
override func sectionIndexTitles(for tableView: UITableView) -> [String]?
{
return indexOfNumbers
}
}
What could I do?
Thanks
I believe you need to comment out or remove the following delegate function.
override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int
{
let temp = indexOfNumbers as NSArray
return temp.index(of: title)
}
Related
I am trying to create UITableview with cells, identical to the iPhone settings screenshot.
It is part of my homework so i have to do it all in UITableview.
this is what I did with my code, but everything is red and full with errors. I tried to do it following the samples from lessons but it kinda looks all wrong.
Please, help me understand how this thing works and what is wrong.
import UIKit
struct Lines{
var image: [UIImage] = []
var title: [String] = []
}
class Titles {
static func titles() -> [Lines]{
return [
Lines(image: UIImage[ systemName: "airplane" ,"wifi.square.fill", "bitcoinsign.circle.fill", "iphone.homebutton.radiowaves.left.and.right", "personalhotpot" ], title: ["Авиарежим" , "Wi-fi", "Bluetooth", "Сотовая связь", "Режим модема"]),
Lines(image: UIImage[ systemName: "bell.badge.fill" ,"speaker.wave.3.fill", "moon.fill", "iphone.homebutton.radiowaves.left.and.right", "clock.fill" ], title: ["Уведомления", "Звуки,тактильные сигналы", "Не беспокоить", "Экранное время"]),
Lines(image: UIImage[ systemName: "gear" ,"switch.2", "display" ] , title: ["Общие", " Control Centre", "Экран и яркость"])
]
}
}
class SecondTableViewController: UITableViewController {
var lines = Titles.titles()
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension SecondTableViewController: UITableViewDataSource, UITableViewDelegate{
func numberOfSections(in tableView: UITableView) -> Int {
return titles.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles[section].title.count
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "SectionCell") as! TableViewCell
let title = titles[section]
cell.image = Lines.image
cell.titleLabel.text = Lines.title
return cell
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SecondTableViewCell") as! TableViewCell
let name = titles[indexPath.section].title[indexPath.row]
cell.image = Lines.image
cell.titleLabel.text = Lines.title
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
Thank you!
You use the wrong property name :
func numberOfSections(in tableView: UITableView) -> Int {
// titles is not defined
return titles.count
}
You must use :
func numberOfSections(in tableView: UITableView) -> Int {
return lines.count
}
Same for the other methods. In cellForRow :
let name = titles[indexPath.section].title[indexPath.row]
Let image = titles[indexPath.section].image[indexPath.row]
Should be replaced by :
let name = lines[indexPath.section].title[indexPath.row]
For viewFirHeader you use a cell which is usually not what is done. You have no title for each lines array. You may have to think again what you want to use. The way you organise your data may also be rethink as you have 2 different array for images and titles.
I'm fetching data from a Realm database and I want to populate a tableview with 2 sections: Autobots and Decepticons. But section property from TableView is returning just the position 0 from the array. Please help me, Thank you.
import UIKit
import RealmSwift
class ViewController: UIViewController, UITableViewDataSource {
let sections = ["Autobots","Decepticons"]
var autobotsNames : [String] = []
var decepticonsNames : [String] = []
var allTransformersNames = [[String]]()
override func viewDidLoad() {
super.viewDidLoad()
print(Realm.Configuration.defaultConfiguration.fileURL!)
let transformers = Transformers()
let transformersData = transformers.TransformersData()
for data in transformersData {
if data.group == "A" {
autobotsNames.append(data.name)
}
else {
decepticonsNames.append(data.name)
}
}
allTransformersNames.append(autobotsNames)
allTransformersNames.append(decepticonsNames)
print(autobotsNames)
print(decepticonsNames)
print(allTransformersNames)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.allTransformersNames[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Transformers", for: indexPath)
cell.textLabel?.text = self.allTransformersNames[indexPath.section][indexPath.row]
return cell
}
}
Print Results
TableView showing 1 section
I have a problem that I want to show a tableview, but separated in sections by the "status" of each item. I know how to do it with a simple string array, but I can't get to make this work with a class (Aluno) array, here's my code so far:
import UIKit
class DeliveriesTVC: UITableViewController {
let sections = ["Delivered", "Not Delivered"]
var studentList: [Array<Student>] = [[], []]
override func viewDidLoad() {
super.viewDidLoad()
for i in 0...5{
studentList[0].append(Student(alunoNome: "Aluno \(i)", alunoImg: "dani_test", alunoStatus: "Delivered"))
}
for i in 6...10{
studentList[1].append(Student(alunoNome: "Aluno \(i)", alunoImg: "dani_test", alunoStatus: "Not Delivered"))
}
self.title = "Deliveries"
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cellEntrega = tableView.dequeueReusableCell(withIdentifier: "EntregaCell", for: indexPath) as? EntregaCell {
let entregaCell = studentList[indexPath.section][indexPath.row]
// here i call a function in my TableViewCell class that update the cell itself
cellEntrega.updateAlunoUI(Aluno: entregaCell)
return cellEntrega
} else {
return UITableViewCell()
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listaAlunos[section].count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section]
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
}
In the output, i just get the "first section" showing, and without a name, even with me setting the name of each section and the number of sections. I've looked everywhere but i couldn't find a solution.
Your numberOfSections and titleForHeader methods are wrong, it should be
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section]
}
Additionally, you should return self.sections.count instead of return 2 in numberOfSections being hardcoded as in case you add another object to the array, you will have to change the 2 to whatever elements the array has now.
For your numberOfSectionInTableView function, shouldn't it be override func numberOfSectionsInTableView(in tableView: UITableView) -> Int {
return 2
} with a in in front of the tableView: UITableView?
I don't see where you connect your UITableView's delegate and datasource.
Here is a tutorial to show your about using UITableView.
Take a look at "Basic Table View" - "Step 3: Set the datasource and delegate"
I have a dictionary and importing information from my database. I need to put it specifically in the right section in my table view. All the information is provided, if you need more detail or code I will provide it.
Dictionary output ["March 27": ["do the dishes", "take out the trash"], "March 29": ["Walk the dog", "Water the plants"], "March 28": ["Clean the house"]]
var date = ["March 27", "March 28", "March 29"]
func numberOfSections(in tableView: UITableView) -> Int {
return date.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return date[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "cell") as! Chores
//Having trouble on what to do here
return cell
}
That's how you can do, I think this is self explanatory:
var output = ["March 27": ["do the dishes", "take out the trash"], "March 29": ["Walk the dog", "Water the plants"], "March 28": ["Clean the house"]]
var date = Array(output.keys)
func numberOfSections(in tableView: UITableView) -> Int {
return date.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return date[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return output[date[section]]?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "cell") as! Chores
var value = output[date[indexPath.section]]?[indexPath.row] ?? ""
cell.textLabel.text = value
return cell
}
// Edited in number of rows you have:
output[date[section]]?.count
it's exactly like this, this mostly gives you optionals but I will ignore it in this example:
let keyForSection = date[section]
let arrayOfStringsForKey = output[keyForSection]
let numberOfRows = arrayOfStringsForKey.count
you do similar stuff to get the actual value but instead of count you pass index of the row you want the value from
let value = arrayOfStringsForKey[rowNumber]
Lets consider this example:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var names = ["Vegetables": ["Tomato", "Potato", "Lettuce"], "Fruits": ["Apple", "Banana"]]
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier:"test")
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return ???
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int{
return names.count
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]!{
return ???
}
func tableView(tableView: UITableView,
titleForHeaderInSection section: Int) -> String?{
return ????
}
}
let's assume that we need that the keys (fruits and vegetables) of the dictionary are the number of sections, plus they will be the titles of the sections. The items of the keys (eg apples and banana) will be the rows of each section. How can I implement this in my code? I know it might be easy but I couldn't figure it out my self.
You can use struct for that and here is example:
import UIKit
class TableViewController: UITableViewController {
var names = ["Vegetables": ["Tomato", "Potato", "Lettuce"], "Fruits": ["Apple", "Banana"]]
struct Objects {
var sectionName : String!
var sectionObjects : [String]!
}
var objectArray = [Objects]()
override func viewDidLoad() {
super.viewDidLoad()
for (key, value) in names {
println("\(key) -> \(value)")
objectArray.append(Objects(sectionName: key, sectionObjects: value))
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return objectArray.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objectArray[section].sectionObjects.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
cell.textLabel?.text = objectArray[indexPath.section].sectionObjects[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return objectArray[section].sectionName
}
}
Swift 2
you dictionary example
var dic:Dictionary<String,String> = ["key":"value","key1":"value2"]
Your table
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
var key = Array(self.dic.keys)[indexPath.row]
var value = Array(self.dic.values)[indexPath.row]
cell.text = key + value
}
If you want it sorted use the global sorted function to sort the dictionary.
import UIKit
class TableViewController: UITableViewController {
var names = ["Vegetables": ["Tomato", "Potato", "Lettuce"], "Fruits": ["Apple", "Banana"]]
var namesSorted = [String, Array<String>]()
override func viewDidLoad() {
super.viewDidLoad()
// Sort names
namesSorted = sorted(names) { $0.0 < $1.0} // namesSorted = ["Fruits": ["Apple", "Banana"], "Vegetables": ["Tomato", "Potato", "Lettuce"]]
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return namesSorted.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return namesSorted[section].1.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
cell.textLabel?.text = namesSorted[indexPath.section].1[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return namesSorted[section].0
}
}
All collection types must be Array
var names = [["Tomato", "Potato", "Lettuce"], ["Apple", "Banana"]]
var sectionNames = ["Vegetables", "Fruits"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return names[section].count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int{
return names.count
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]!{
return sectionNames
}
func tableView(tableView: UITableView,
titleForHeaderInSection section: Int) -> String?{
return sectionNames[section]
}
From Apple Documentation :
var keys: LazyForwardCollection<MapCollectionView<Dictionary<Key, Value>, Key>> { get }
Description: A collection containing just the keys of self. Keys appear in the same order as they occur as the .0 member of key-value pairs in self. Each key in the result has a unique value.
names.keys.array returns an Array of the keys.
SO:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return names.keys.array[section].count
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]!{
return names.keys.array
}
func tableView(tableView: UITableView,
titleForHeaderInSection section: Int) -> String?{
return names.keys.array[section]
}
This will work on Any Dictionary with any amount of data(even if it is unknown to the programmer
An easier way to solve this problem is to copy your dictionary into a temporary variable. Use removeFirst to extract the values from the array inside the dictionary.
var itemList=["Grocery":["soap","flour","carrots"],"Vehicles":["oil change","gas","tire rotation"],"Household":["Cable","Tv","cellphone"]]
var itemListTmp :[String:[String]] = [:]
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text=itemListTmp[keysItem[indexPath.section]]?.removeFirst()
//cell.textLabel?.text=itemList[indexPath.section].items[indexPath.row]
return cell
}
Another way of solving this problem is to extract keys and values in separate arrays:
var task=[String](itemList.keys)
var tobeDone=[[String]](itemList.values)
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return task[section]
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text=tobeDone[indexPath.section][indexPath.row]
return cell
}
Similar to https://stackoverflow.com/a/31136537/11098567 answer I would use classes instead of structs, so that you can manipulate or add to your values after it has been placed into the array.
#objc func addToInitialClassInstance() {
let classInstance = Class(property1: String, property2: [CLass2.init(property1: String, property2: String)])
let isAvailable = initialClassInstance.contains { (classInArray) -> Bool in
if classInArray.property == classInstance.property {
classInArray.property2.append(classInstance.property2[0])
return true
}
return false
}
if !isAvailable {
initialClassInstance.append(classInstance)
}
tableView.reloadData()
}