-2

I'm getting an "Index out of range" when populating a UITableView. I don't know why it gives me error. I have a condition statement on my cell creation function which checks for the count of each array and then adds a custom cell on index 0.

If anyone knows about this problem, please tell me the solution. I've been working on it for days and can't seem to figure this one out.

var homeArr: [services] = []
var autoArr: [services] = []

Alamofire.request(url_specialist_request_url, method: .post, parameters: parameters).responseJSON {
    response in

    if response.data != nil {
        let json = JSON(data: response.data!)
        let json_count = json.count

        // print(json)

        self.homeArr.append(services(service_name:"",service_icon:"",service_category:""))
        self.autoArr.append(services(service_name:"",service_icon:"",service_category:""))
        self.personalArr.append(services(service_name:"",service_icon:"",service_category:""))

        for i in 0 ..< json_count {
            let categoryId = json[i]["category_id"].string!
            if(categoryId == "1") {
                self.homeArr.append(services(service_name:json[i]["service_name"].string!,service_icon:"\(json[i]["service_icon"].string!)Icon",service_category:json[i]["category_id"].string!))
            } else if(categoryId == "2") {
                self.autoArr.append(services(service_name:json[i]["service_name"].string!,service_icon:"\(json[i]["service_icon"].string!)Icon",service_category:json[i]["category_id"].string!))
            } else {
                self.personalArr.append(services(service_name:json[i]["service_name"].string!,service_icon:"\(json[i]["service_icon"].string!)Icon",service_category:json[i]["category_id"].string!))
            }
        }

        self.tableView.reloadData()
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "serviceCell",for:indexPath) as! servicesCell

    let home_dict = self.homeArr[indexPath.row]
    // ** Index out of range on the following line **
    let auto_dict = self.autoArr[indexPath.row]

    if(self.homeArr.count > 1) {
        if (indexPath.row == 0)
        {
            cell.serviceLabel!.text = "Home"
            cell.contentView.backgroundColor = UIColor.blue
        } else {
            cell.serviceLabel!.text = home_dict.service_name
            cell.serviceIcon!.image = UIImage(named:"\(home_dict.service_icon)")
        }
    }

    if(self.autoArr.count > 1) {
        if (indexPath.row == 0)
        {
            cell.serviceLabel!.text = "Personal"
            cell.contentView.backgroundColor = UIColor.blue
        } else {
            cell.serviceLabel!.text = auto_dict.service_name
            cell.serviceIcon!.image = UIImage(named:"\(auto_dict.service_icon)")
        }
    }

    return cell
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return(homeArr.count + arrAuto.count)
}

This is what I want to achieve

    Home Arr cell

  • value1
  • value2
    • Auto Arr cell

  • value1
  • value2
  • IGNITER
    • 39
    • 1
    • 6
    • 2
      Start by pointing out the exact line of code causing the error. – rmaddy Nov 17 '17 at 16:47
    • @IGNITER you did return(homeArr.count + arrAuto.count) means if you have 10 values in each array, the number of rows goes 20. Now in cell method you are doing self.homeArr[indexPath.row] and self.autoArr[indexPath.row] . Your array holds 10 index but method is calling for 20 so index out of range. – Tushar Sharma Nov 17 '17 at 16:50
    • @TusharSharma What do you think would be the work around? I have no idea. – IGNITER Nov 17 '17 at 16:58
    • @rmaddy it errors this line let auto_dict = self.autoArr[indexPath.row] – IGNITER Nov 17 '17 at 16:59
    • How do you want to show your data in the table view? You have two arrays of data that you seem to want to display. Do you want a row for each value in the `homeArr` and a row for each value in `autoArr`? Do you want to show all of the rows for `autoArr` after the rows for the `homeArr`? Please explain your goal. – rmaddy Nov 17 '17 at 17:09
    • @rmaddy Basically, I want to display the content of homeArr and autoArr. – IGNITER Nov 17 '17 at 17:10
    • Please read my comment again. How do you want to display the content of those two arrays? Be specific and clear. – rmaddy Nov 17 '17 at 17:11
    • @rmaddy I've edited my post, and added what I want to achieve on my table. please refer above, thanks. – IGNITER Nov 17 '17 at 17:19
    • @IGNITER That doesn't clear up anything at all. That is now more confusing. – rmaddy Nov 17 '17 at 17:22
    • @rmaddy actually, all i want is a header section for each category types. – IGNITER Nov 17 '17 at 17:28

    1 Answers1

    1

    Create two sections One for HomeArr and one for AutoArr. I believe for each section you wanna show a additional cell with some title. So below code should help you.

    extension ViewController : UITableViewDataSource {
        func numberOfSections(in tableView: UITableView) -> Int {
            return 2
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            if section == 0 {
                return (homeArr.count > 0) ?  homeArr.count + 1 : 0
            }
            else {
                return (autoArr.count > 0) ?  autoArr.count + 1 : 0
            }
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "serviceCell",for:indexPath) as! servicesCell
            if indexPath.section == 0 {
                if (indexPath.row == 0)
                {
                    cell.serviceLabel!.text = "Home"
                    cell.contentView.backgroundColor = UIColor.blue
                } else {
                    let home_dict = self.homeArr[indexPath.row - 1]
                    cell.serviceLabel!.text = home_dict.service_name
                    cell.serviceIcon!.image = UIImage(named:"\(home_dict.service_icon)")
                }
            }
            else {
                if (indexPath.row == 0)
                {
                    cell.serviceLabel!.text = "Personal"
                    cell.contentView.backgroundColor = UIColor.blue
                } else {
                    let auto_dict = self.autoArr[indexPath.row - 1]
                    cell.serviceLabel!.text = auto_dict.service_name
                    cell.serviceIcon!.image = UIImage(named:"\(auto_dict.service_icon)")
                }
            }
            return cell
        }
    }
    

    EDIT:

    As pointed out by rmaddy in comments below

    Why the extra row in each section? Why not use a section header instead?

    As we are not aware of OP's exact requirement I am updating my code to show section title as well.

     extension ViewController : UITableViewDataSource {
        func numberOfSections(in tableView: UITableView) -> Int {
            return 2
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            if section == 0 {
                return homeArr.count
            }
            else {
                return autoArr.count
            }
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "serviceCell",for:indexPath) as! servicesCell
            if indexPath.section == 0 {
                let home_dict = self.homeArr[indexPath.row]
                cell.serviceLabel!.text = home_dict.service_name
                cell.serviceIcon!.image = UIImage(named:"\(home_dict.service_icon)")
            }
            else {
                let auto_dict = self.autoArr[indexPath.row]
                cell.serviceLabel!.text = auto_dict.service_name
                cell.serviceIcon!.image = UIImage(named:"\(auto_dict.service_icon)")
            }
            return cell
        }
    
        func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
            if section == 0 {
                return "Home Arr cell"
            }
            else {
                return "Auto Arr cell"
            }
        }
    }
    
    Sandeep Bhandari
    • 19,999
    • 5
    • 45
    • 78