Swift - 使用节和源更新/添加/删除表视图上的项

时间:2018-02-10 17:46:43

标签: ios swift tableview

如何使用部分及其来源更新/添加/删除表格视图中的项目?

尝试更新单元格时遇到问题。有时它会发生在删除和添加上。

似乎部分上的问题正在触发它。

1-数据从服务器的JSON响应加载。

2 - 此数据按字母顺序排序,并创建基于名称中第一个字母的部分,将每个客户端添加到其索引字母。

我正在添加到打印屏幕:

在:

initial list

后:

misplaced indexes

我改名为'碗'到碗2'它创造了'一个新的条目,保持旧的和新的价值。如果我刷新(拉),它就会被修复。

此外,有时,它会删除Abc MacDon'刷新后,它会得到修复。

class ClientsViewController:  UITableViewController {

var sortedFirstLetters: [String] = []
var sections: [[Client]] = [[]]
var tableArray = [Client]()
var client: Client?
var wasDeleted: Bool?
var refresher: UIRefreshControl!

@IBOutlet weak var noClientsLabel: UILabel!
@IBOutlet var noClientsView: UIView!

@IBAction func unwindToClients(sender: UIStoryboardSegue) {

    if let sourceViewController = sender.source as? ClientViewController,
        let client = sourceViewController.client,
        let wasDeleted = sourceViewController.wasDeleted {

        if(wasDeleted) {
            if let selectedIndexPath = tableView.indexPathForSelectedRow {
                print("Delteted")
                tableArray.remove(at: selectedIndexPath.row)
//                    DispatchQueue.main.async {
//                        // Deleting the row in the tableView
//                        if self.tableView.numberOfRows(inSection: selectedIndexPath.section) > 1 {
//                            self.tableView.deleteRows(at: [selectedIndexPath], with: UITableViewRowAnimation.bottom)
//                        } else {
//                            let indexSet = NSMutableIndexSet()
//                            indexSet.add(selectedIndexPath.section)
//                            self.tableView.deleteSections(indexSet as IndexSet, with: UITableViewRowAnimation.bottom)
//                        }
//
//                    }
            }

        }
        else {
            if let selectedIndexPath = tableView.indexPathForSelectedRow {
                // Update an existing client.
                tableArray[selectedIndexPath.row] = client
                //tableView.reloadRows(at: [selectedIndexPath], with: .automatic)
                print("update")
                print(tableArray)
            }
            else {
                // Add a client.
                tableArray.append(client)
                print("add")
            }
        }
        self.prepareData()
        DispatchQueue.main.async {

            self.tableView.reloadData()
        }

    }
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let secondScene = segue.destination as! ClientViewController
    if segue.identifier == "ShowDetail", let indexPath = self.tableView.indexPathForSelectedRow {
        let currentPhoto = sections[indexPath.section][indexPath.row]
        secondScene.client = currentPhoto
    }
    else if segue.identifier == "AddItem" {
        print("add")
    }
    else {
        fatalError("The selected cell is not being displayed by the table")
    }
}

@objc func handleRefresh(_ refreshControl: UIRefreshControl) {
    getClients()
}

}

extension ClientsViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    self.refreshControl?.addTarget(self, action: #selector(ClientsViewController.handleRefresh(_:)), for: UIControlEvents.valueChanged)
    tableView.backgroundView = nil
    noClientsLabel.text = ""
    getClients() //for only the 1st time ==> when view is created ==> ok ish
}


override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    if(self.tableArray.count > 0) {
        return sortedFirstLetters[section]
    }
    else {
        return ""
    }
}

override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
    return sortedFirstLetters
}

override func numberOfSections(in tableView: UITableView) -> Int {
    return sections.count
}


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let item = sections[indexPath.section][indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: "ClientCell", for: indexPath)
    cell.textLabel?.text = item.name
    cell.detailTextLabel?.text = item.city + " - " + item.province
    return cell
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return sections[section].count
}

func getClients() {
    print("called server")
    self.refreshControl?.beginRefreshing()
    self.tableView.setContentOffset(CGPoint(x:0, y:-100), animated: true)

    makeRequest(endpoint: "api/clients/all",
                parameters: [:],
                completionHandler: { (container : ApiContainer<Client>?, error : Error?) in
                    if let error = error {
                        print("error calling POST on /getClients")
                        print(error)
                        return
                    }
                    self.tableArray = (container?.result)!

                    self.prepareData()
                    DispatchQueue.main.async {
                        if(self.tableArray.isEmpty)
                        {
                            self.noClientsLabel.text = "bNo Clients"
                            self.tableView.backgroundView?.isHidden = false
                            self.noClientsLabel.text = ""
                            print("all")
                        }
                        else{
                            print("nothing")
                        }
                        self.tableView.reloadData()
                        self.refreshControl?.endRefreshing()
                    }
    } )
}

//sorts and makes the index
func prepareData() {
    let firstLetters = self.tableArray.map { $0.nameFirstLetter }
    let uniqueFirstLetters = Array(Set(firstLetters))

    self.sortedFirstLetters = uniqueFirstLetters.sorted()
    self.sections = self.sortedFirstLetters.map { firstLetter in
        return self.tableArray
            .filter { $0.nameFirstLetter == firstLetter }
            .sorted { $0.name < $1.name }
    }
}

}

STRUCT

struct Client: Codable {
var client_id: Int!
let name: String!
let postal_code: String!
let province: String!
let city: String!
let address: String!

init(name: String, client_id: Int! = nil, postal_code: String, province: String, city: String, address: String) {
    self.client_id = client_id
    self.name = name
    self.postal_code = postal_code
    self.province = province
    self.city = city
    self.address = address

}

var nameFirstLetter: String {
    return String(self.name[self.name.startIndex]).uppercased()
}

}
与Hardik进行一些互动后的

代码

import UIKit
import Foundation

class ClientsViewController:  UITableViewController {

    var sortedFirstLetters: [String] = []
    var sections: [[Client]] = [[]]
  //  var tableArray = [Client]()
    var tableArray : [Client] = [Client]()
    var client: Client?
    var wasDeleted: Bool?
    var refresher: UIRefreshControl!

    @IBOutlet weak var noClientsLabel: UILabel!
    @IBOutlet var noClientsView: UIView!

    @IBAction func unwindToClients(sender: UIStoryboardSegue) {

        if let sourceViewController = sender.source as? ClientViewController,
            let client = sourceViewController.client,
            let wasDeleted = sourceViewController.wasDeleted {

            if(wasDeleted) {
                if let index = self.tableArray.index(where: { (item) -> Bool in
                    item.client_id == client.client_id
                }) {
                    self.tableArray.remove(at: index)
                    print("Delteted")
                    // Find the client in the tableArray by the client id and remove it from the tableArray
                    // I am writing an example code here, this is not tested so just get the logic from here.
                    //self.tableArray.remove(at: selectedIndexPath.row)
                }

            }
            else {
                if self.tableArray.contains(where: { (item) -> Bool in
                    item.client_id == client.client_id
                }) {
                    //Find the item in the tableArray by the client id and update it there too
                    // I am writing an example code here, this is not tested so just get the logic from here.
                    //if let index = self.tableArray.index(where: { (item) -> Bool in
                    //    item.id == client.id
                    //}) {
                    self.tableArray[index] = client
                    //self.tableArray.replace(client, at: index)
                    //}
                    print("update")
                    print(tableArray)
                }
                else {
                    // Add a client.
                    tableArray.append(client)
                    print("add")
                }
            }
            // Now update the sections Array and it will have all the correct values
            self.prepareData()
            DispatchQueue.main.async {

                self.tableView.reloadData()
            }

//            if(wasDeleted) {
//                if let selectedIndexPath = tableView.indexPathForSelectedRow {
//                    print("Delteted")
//                    sections[selectedIndexPath.section].remove(at: selectedIndexPath.row)
//                }
//
//            }
//            else {
//                if let selectedIndexPath = tableView.indexPathForSelectedRow {
//                    // Update an existing client.
//                    sections[selectedIndexPath.section][selectedIndexPath.row] = client
//                    //tableView.reloadRows(at: [selectedIndexPath], with: .automatic)
//                    print("update")
//                    print(tableArray)
//                }
//                else {
//                    // Add a client.
//                    tableArray.append(client)
//                    print("add")
//                    self.prepareData()
//                }
//            }
//
//            DispatchQueue.main.async {
//
//                self.tableView.reloadData()
//            }







//            if(wasDeleted) {
//                if let selectedIndexPath = tableView.indexPathForSelectedRow {
//                    print("Delteted")
//                    tableArray.remove(at: selectedIndexPath.row)
////                    DispatchQueue.main.async {
////                        // Deleting the row in the tableView
////                        if self.tableView.numberOfRows(inSection: selectedIndexPath.section) > 1 {
////                            self.tableView.deleteRows(at: [selectedIndexPath], with: UITableViewRowAnimation.bottom)
////                        } else {
////                            let indexSet = NSMutableIndexSet()
////                            indexSet.add(selectedIndexPath.section)
////                            self.tableView.deleteSections(indexSet as IndexSet, with: UITableViewRowAnimation.bottom)
////                        }
////
////                    }
//                }
//
//            }
//            else {
//                if let selectedIndexPath = tableView.indexPathForSelectedRow {
//                    // Update an existing client.
//                    tableArray[selectedIndexPath.row] = client
//                    //tableView.reloadRows(at: [selectedIndexPath], with: .automatic)
//                    print("update")
//                    print(tableArray)
//                }
//                else {
//                    // Add a client.
//                    tableArray.append(client)
//                    print("add")
//                }
//            }
//            self.prepareData()
//            DispatchQueue.main.async {
//
//                self.tableView.reloadData()
//            }

        }
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let secondScene = segue.destination as! ClientViewController
        if segue.identifier == "ShowDetail", let indexPath = self.tableView.indexPathForSelectedRow {
            let currentPhoto = sections[indexPath.section][indexPath.row]
            secondScene.client = currentPhoto
        }
        else if segue.identifier == "AddItem" {
            print("add")
        }
        else {
            fatalError("The selected cell is not being displayed by the table")
        }
    }

    @objc func handleRefresh(_ refreshControl: UIRefreshControl) {
        getClients()
    }

}

extension ClientsViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.refreshControl?.addTarget(self, action: #selector(ClientsViewController.handleRefresh(_:)), for: UIControlEvents.valueChanged)
        tableView.backgroundView = nil
        noClientsLabel.text = ""
        getClients() //for only the 1st time ==> when view is created ==> ok ish
    }


    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        if(self.tableArray.count > 0) {
            return sortedFirstLetters[section]
        }
        else {
            return ""
        }
    }

    override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
        return sortedFirstLetters
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let item = sections[indexPath.section][indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "ClientCell", for: indexPath)
        cell.textLabel?.text = item.name
        cell.detailTextLabel?.text = item.city + " - " + item.province
        return cell
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections[section].count
    }

    func getClients() {
        print("called server")
        self.refreshControl?.beginRefreshing()
        self.tableView.setContentOffset(CGPoint(x:0, y:-100), animated: true)

        makeRequest(endpoint: "api/clients/all",
                    parameters: [:],
                    completionHandler: { (container : ApiContainer<Client>?, error : Error?) in
                        if let error = error {
                            print("error calling POST on /getClients")
                            print(error)
                            return
                        }
                        self.tableArray = (container?.result)!

                        self.prepareData()
                        DispatchQueue.main.async {
                            if(self.tableArray.isEmpty)
                            {
                                self.noClientsLabel.text = "bNo Clients"
                                self.tableView.backgroundView?.isHidden = false
                                self.noClientsLabel.text = ""
                                print("all")
                            }
                            else{
                                print("nothing")
                            }
                            self.tableView.reloadData()
                            self.refreshControl?.endRefreshing()
                        }
        } )
    }

    //sorts and makes the index
    func prepareData() {
        let firstLetters = self.tableArray.map { $0.nameFirstLetter }
        let uniqueFirstLetters = Array(Set(firstLetters))

        self.sortedFirstLetters = uniqueFirstLetters.sorted()
        self.sections = self.sortedFirstLetters.map { firstLetter in
            return self.tableArray
                .filter { $0.nameFirstLetter == firstLetter }
                .sorted { $0.name < $1.name }
        }
    }

}

1 个答案:

答案 0 :(得分:1)

您正在编辑错误的数据源。您应该编辑或更新sections数组而不是tableArray

unwindToClients更改您的代码:

   if(wasDeleted) {
        if let selectedIndexPath = tableView.indexPathForSelectedRow {
            print("Delteted")
            tableArray.remove(at: selectedIndexPath.row)
        }
    }
    else {
        if let selectedIndexPath = tableView.indexPathForSelectedRow {
            // Update an existing client.
            tableArray[selectedIndexPath.row] = client
            //tableView.reloadRows(at: [selectedIndexPath], with: .automatic)
            print("update")
            print(tableArray)
        }
        else {
            // Add a client.
            tableArray.append(client)
            print("add")
        }
    }
    self.prepareData()
    DispatchQueue.main.async {

        self.tableView.reloadData()
    }

用这个:

    if(wasDeleted) {
        if let selectedIndexPath = tableView.indexPathForSelectedRow {
            print("Delteted")
            sections[selectedIndexPath.section].remove(at: selectedIndexPath.row)
        }

    }
    else {
        if let selectedIndexPath = tableView.indexPathForSelectedRow {
            // Update an existing client.
            sections[selectedIndexPath.section][selectedIndexPath.row] = client
            //tableView.reloadRows(at: [selectedIndexPath], with: .automatic)
            print("update")
            print(tableArray)
        }
        else {
            // Add a client.
            tableArray.append(client)
            print("add")
            self.prepareData()
        }
    }

    DispatchQueue.main.async {

        self.tableView.reloadData()
    }

要修复错误的部分标题,请尝试执行以下操作:

    if(wasDeleted) {
        if let index = self.tableArray.index(where: { (item) -> Bool in
            item.id == client.id
        }) {
            print("Delteted")
            // Find the client in the tableArray by the client id and remove it from the tableArray
            // I am writing an example code here, this is not tested so just get the logic from here.
            //self.tableArray.remove(at: index)
        }

    }
    else {
        if self.tableArray.contains(client) {
            //Find the item in the tableArray by the client id and update it there too
            // I am writing an example code here, this is not tested so just get the logic from here.
            //if let index = self.tableArray.index(where: { (item) -> Bool in
            //    item.id == client.id
            //}) {
            //    self.tableArray.replace(client, at: index)
            //}
            print("update")
            print(tableArray)
        }
        else {
            // Add a client.
            tableArray.append(client)
            print("add")
        }
    }
    // Now update the sections Array and it will have all the correct values
    self.prepareData()
    DispatchQueue.main.async {

        self.tableView.reloadData()
    }