TableView - “Thread 1: Fatal error: Index out of range in Swift” - swift

I'm pulling data from the database, I'm having no problems with data, but I'm having trouble transferring this data to the text in the Cell. I think I'm having a problem with the numberOfRowsInSection count. I want to add as much data as the sum of the two data, but I'm having trouble this way.
class ChatRoomViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var bilgiCevap = [String]()
var bilgiKullanıcı = [String]()
override func viewDidLoad() {
super.viewDidLoad()
FCevap()
chatTableView.delegate = self
chatTableView.dataSource = self
func FCevap(){
let client = SQLClient.sharedInstance()!
client.connect("...", username: "...", password: "...", database: "...") { success in
client.execute("SELECT ... FROM ... WHERE . LIKE '\(self.form_no)' AND ... LIKE '0'", completion: { (_ results: ([Any]?)) in
for table in results as! [[[String:AnyObject]]] {
for row in table {
for (_, value) in row {
if let intVal = value as? String {
self.bilgiKullanıcı.append(String(intVal))
}} }}
DispatchQueue.main.async {
self.Kullanici()
self.chatTableView.reloadData()}
client.disconnect() }) }
}
func Kullanıcı(){
let client = SQLClient.sharedInstance()!
client.connect("...", username: "...", password: "...", database: "...") { success in
client.execute("SELECT ... FROM ... WHERE ... LIKE '\(self.form_no)' AND ... LIKE '1'", completion: { (_ results: ([Any]?)) in
for table in results as! [[[String:AnyObject]]] {
for row in table {
for (_, value) in row {
if let intVal = value as? String {
self.bilgiCevap.append(String(intVal))
}} }}
DispatchQueue.main.async {self.chatTableView.reloadData()}
client.disconnect() }) }
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = chatTableView.dequeueReusableCell(withIdentifier: "chatCell") as! ChatCell
let messageGıden = self.bilgiKullanıcı[indexPath.row]
cell.chatTextView.text = messageGıden
cell.usernameLabel.text = "..."
cell.setBubbleType(type: .incoming)
let messageGelen = self.bilgiCevap[indexPath.row]
cell.chatTextView2.text = messageGelen
cell.userNameLabel2.text = "Kullanıcı"
cell.setBubbleType2(type: .outgoing)
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return bilgiCevap.count + bilgiKullanici.count
}
}

if you have data sources you need to take two Sections in number of section delegate.
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
And in numberOfRows section
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return dataSource1.count
} else {
return dataSource2.count
}
}
and then inside cellFor rowAt delegate
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let data = dataSource1[indexPath.row]
} else {
let data = dataSource2[indexPath.row]
}
}

Related

Append CellType Index Out Of Range Error Swift

After appending a new cellType my locationTableViewCell is giving an error at let place = places[indexPath.row] while entering text inside the text field search bar.
private func locationTableViewCell(indexPath: IndexPath) -> PostSelectLocationTableViewCell {
let locationCell = tableView.dequeueReusableCell(forIndexPath: indexPath) as PostSelectLocationTableViewCell
let place = places[indexPath.row]
locationCell.configure(model: place)
return locationCell
}
locationInteractor.didPlacesLoaded = { [weak self] places in
DispatchQueue.main.async {
self?.places = places
if self?.places.isEmpty == true {
self?.cellTypes = [.empty]
} else {
self?.cellTypes += Array(repeating: .location, count: self?.places.count ?? 0)
}
self?.tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellTypes.count
}
before appending .currentLocation everything was peachy. But now when I enter a text to search between locations, it crashes with Index Out Of Range error. I have tried to let place = places[indexPath.row + 1] and let place = places[indexPath.row - 1] but it was ineffective.
locationInteractor.didCurrrentPlaceLoaded = { [weak self] currentPlace in
self?.currentLocation = currentPlace
self?.cellTypes.append(.currentLocation)
self?.tableView.reloadData()
}
The problem was that my previous numberOfRowsInSection was as below.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellTypes.count
}
so this was causing me index out-of-range error.
After changing numberOfRowsInSection as below for each specific celltype my error is gone.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// sponsored by Serhat Sezen
if !places.isEmpty {
return places.count
} else {
return cellTypes.count
}
}

Problem assigning data to tableview - Swift

Although I load the data into the gifsa string array in the function, I cannot see the gifsa data in the tableView. gifsa data does not appear in tableView. The data is loading data in the veriCek() function. However, it does not load data into the imageView found in cell. What is the problem?
class NewDegisimController: UITableViewController {
var gifsa: [String] = []
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return gifsa.count
}
override func viewDidLoad() {
super.viewDidLoad()
veriCek()
}
func veriCek(){
let client = SQLClient.sharedInstance()!
client.connect("...", username: "...", password: "...", database: "...") { success in
client.execute("SELECT ... FROM ...", completion: { (_ results: ([Any]?)) in
for table in results as! [[[String:AnyObject]]] {
for row in table {
for (_, value) in row {
if let intVal = value as? String {
self.gifsa.append(String(intVal))
}} }}
client.disconnect()
}) }
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
let model = models[indexPath.row]
do {
print("gifsaas",self.gifsa)
let url = URL(string: self.gifsa[indexPath.row])
let data = try Data(contentsOf: url!)
cell.imageView?.image = UIImage(data: data)
cell.textLabel?.text = model.title
}
catch{
print(error)
}
return cell
}
You need to reload
for table in results as! [[[String:AnyObject]]] {
for row in table {
for (_, value) in row {
if let intVal = value as? String {
self.gifsa.append(String(intVal))
}} }}
DispatchQueue.main.async {
self.tableView.reloadData()
}
You just need to call
self.tableView.reload()
in your veriCek() function and you are all set

Add section after 7 cell created in TableView - Swift

I have 2 arrays, one that is containing the sections and another one that is containing the elements for populate the cells of my TableView.
The question is: is it possible to create multiple sections with title after 7 cells?
For example, the array contains 14 elements and sections array 2 elements. I wish that at the beginning will appear "Section 1" then first 7 elements, then "Section 2" then the rest of the elements.
Thank you!
import UIKit
class ChallengesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var titleArray = [""]
var weekSection = ["1","2"]
override func viewDidLoad() {
super.viewDidLoad()
> let url = URL(string:"https://website.com/file.txt")!
> URLCache.shared.removeAllCachedResponses()
> let task = URLSession.shared.dataTask(with:url) { (data, response, error) in
> if error != nil {
> print(error!)
> }
> else {
> if let textFile = String(data: data!, encoding: .utf8) {
> DispatchQueue.main.async {
> self.titleArray = textFile.components(separatedBy: "\n")
> self.tableView.reloadData()
> print(self.titleArray)
> }
> }
> }
> }
> task.resume()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titleArray.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return weekSection.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "challengeCell", for: indexPath) as! ChallengeTableViewCell
cell.labelTitle.text = titleArray[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch (section) {
case 0:
return "Case 0"
case 1:
return "Case 1"
default:
return "Default"
}
}
Update numberOfRowsInSection and cellForRowAt methods like this
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Case \(section)"
}
func numberOfSections(in tableView: UITableView) -> Int {
let lastSection = titleArray.count % 7 == 0 ? 0 : 1
return (titleArray.count/7) + lastSection
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count = titleArray.count - (7*section)
return min(7,count)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "challengeCell", for: indexPath) as! ChallengeTableViewCell
let rowIndex = (indexPath.section*7)+indexPath.row
cell.labelTitle.text = titleArray[rowIndex]
return cell
}
after the edit of the question, this is one of the best answers I think
extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
usage:
#IBOutlet weak var tableView: UITableView!
var titleArray: [[String]] = [[]]
var sectionsCount: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string:"https://website.com/file.txt")!
URLCache.shared.removeAllCachedResponses()
let task = URLSession.shared.dataTask(with:url) { (data, response, error) in
if error != nil {
print(error!)
}
else {
if let textFile = String(data: data!, encoding: .utf8) {
DispatchQueue.main.async {
let myArray = textFile.components(separatedBy: "\n")
self.sectionsCount = myArray.chunked(into: 7).count
self.tableView.reloadData()
print(self.titleArray)
}
}
}
}
task.resume()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sectionsCount
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titleArray[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "challengeCell", for: indexPath) as! ChallengeTableViewCell
let sectionArray = titleArray[indexPath.section]
cell.labelTitle.text = sectionArray[indexPath.row]
return cell
}

swift, numberOfRowsInSection and cellForRowAt functions don't return values

I have an issue, numberOfRowsInSection and cellForRowAt functions don't return values. I need to return name and price from coincap.io/front API into tableView. I tried to change return values to integer and it works fine, but anyway I can't return another values.
Here is code:
import UIKit
import Alamofire
import SwiftyJSON
class Currency : NSObject {
var name : String!
var price : Double!
init(name : String, price : Double) {
self.name = name
self.price = price
}
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
let DATA_URL : String = "http://coincap.io/front"
var currencies = [Currency]()
var counter = 0
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
getData(url: DATA_URL)
}
func getData(url: String) {
Alamofire.request(url, method: .get).responseJSON { response in
if response.result.isSuccess {
print("Success! Got the data")
let dataJSON : JSON = JSON(response.result.value!)
// print(dataJSON)
self.updateData(json: dataJSON)
} else {
print("Error \(String(describing: response.result.error))")
}
}
}
func updateData(json: JSON) {
for (_, current) in json{
currencies.append(Currency(name: current["long"].stringValue, price: current["price"].doubleValue))
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return NSInteger(counter)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "currencyCell", for: indexPath)
let current = currencies[indexPath.row]
cell.textLabel?.text = current.name
cell.detailTextLabel?.text = "\(current.price!)"
return cell
}
}
You have to call reload
func getData(url: String) {
Alamofire.request(url, method: .get).responseJSON { response in
if response.result.isSuccess {
print("Success! Got the data")
let dataJSON : JSON = JSON(response.result.value!)
// print(dataJSON)
self.updateData(json: dataJSON)
DispatchQueue.main.async {self.tableView.reloadData()}
} else {
print("Error \(String(describing: response.result.error))")
}
}
}
Also replace
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return NSInteger(counter)
}
with
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currencies.count
}

How to make alphabetical section with contacts in tableView in swift

I'm new to Swift and I have arrays made with CNContact(familyName, givenName, phoneNumber).
I'd like to make name contacts alphabetical order and group them in sections in order to put them in the "titleForHeaderInSection" as below.
Does anyone know how to group and put it into titleForHeaderInSection??
struct AddressModel {
let nameAndPhone: [AddressContact]
}
struct AddressContact {
let contact: CNContact
}
class AddressViewController: UITableViewController {
var addressArray = [AddressModel]()
private func fetchContacts() {
print("Attempting to fetch contacts today")
let store = CNContactStore()
store.requestAccess(for: .contacts) { (granted, err) in
if let err = err {
print("Failed to request access:", err)
return
}
if granted {
let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactPhoneNumbersKey] as [Any]
let request = CNContactFetchRequest(keysToFetch: keys as! [CNKeyDescriptor])
request.sortOrder = CNContactSortOrder.userDefault
do {
var addressContact = [AddressContact]()
try store.enumerateContacts(with: request, usingBlock: { (contact, stop) in
addressContact.append(AddressContact(contact: contact))
})
let nameAndPhone = AddressModel(nameAndPhone: addressContact)
self.addressArray = [nameAndPhone]
} catch let err {
print("Failed to enumerate contacts:", err)
}
} else {
print("Access denied..")
}
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Section \(section)"
}
override func numberOfSections(in tableView: UITableView) -> Int {
return self.addressArray.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.addressArray[section].nameAndPhone.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let nameAndPhone = addressArray[indexPath.section].nameAndPhone[indexPath.row]
let fullName = nameAndPhone.contact.familyName + nameAndPhone.contact.givenName
cell.textLabel?.text = fullName
return cell
}
Try this
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
// ...
}
For sorting section title try the closure:
sectionTitle = sectionTitle.sorted(by: { $0 < $1 }) // First argument smaller then second argument.