gpt4 book ai didi

ios - Swift - 在 TableView 的某个部分中更新或插入一行,而无需重新加载所有数据

转载 作者:行者123 更新时间:2023-11-30 11:48:21 25 4
gpt4 key购买 nike

如何在表格 View 中更新或插入行而不重新加载所有数据?

在 ClientsViewController 中,客户端列表按字母顺序显示并按部分分隔(客户端名称的第一个字母)。

当我更新客户端时,表格 View 显示同一客户端的 2 个条目(旧条目和新条目)。当我尝试添加客户端时,它崩溃了。

我认为问题出在索引上。

class ClientsViewController:  UITableViewController {

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

@IBOutlet var noClientsView: UIView!

@IBAction func unwindToClients(sender: UIStoryboardSegue) {

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

if let selectedIndexPath = tableView.indexPathForSelectedRow {
// Update an existing client.
tableArray[selectedIndexPath.row] = client
tableView.reloadRows(at: [selectedIndexPath], with: .automatic)
}
else {
// Add a client.
let newIndexPath = IndexPath(row: tableArray.count, section: 0)
tableArray.append(client)
tableView.insertRows(at: [newIndexPath], with: .automatic)
}


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 }
}

// 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()
refreshControl.endRefreshing()
}

}

extension ClientsViewController {

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

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
getClients() // not a good idea to make a request to the server everytime the view appears on the screen.
}

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]? {
print(sortedFirstLetters)
return sortedFirstLetters
}

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


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

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

func getClients() {

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 {
self.tableView.reloadData()
}
} )
}

//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 }
}
}

}

波纹管是 ClientViewController 和 Client 结构。

class ClientViewController: UITableViewController, UIPickerViewDelegate, UIPickerViewDataSource {

@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var addressTextField: UITextField!
@IBOutlet weak var cityTextField: UITextField!
@IBOutlet weak var provinceTextField: UITextField!
@IBOutlet weak var postalCodeTextField: UITextField!
@IBOutlet weak var contactsLabel: UILabel!

let numberOfRowsAtSection: [Int] = [4, 2]
var client: Client?
var selectedProvince: String?

override func viewWillAppear(_ animated: Bool) {

self.title = "New"
if (client?.client_id) != nil {
self.title = "Edit"
nameTextField.text = client?.name
provinceTextField.text = client?.province
cityTextField.text = client?.city
addressTextField.text = client?.address
postalCodeTextField.text = client?.postal_code
selectedProvince = client?.province
}
}


@objc func save(sender: UIButton!) {
let name = nameTextField.text ?? ""
let address = addressTextField.text ?? ""
let city = cityTextField.text ?? ""
let province = selectedProvince ?? ""
let postal_code = postalCodeTextField.text ?? ""
var endPoint: String

if (client?.client_id) != nil {
endPoint = "api/clients/update"
} else {
endPoint = "api/clients/add"
}

client = Client(name:name, client_id: client?.client_id, postal_code: postal_code, province: province, city: city, address: address)
let requestBody = makeJSONData(client)

makeRequestPost(endpoint: endPoint,
requestType: "POST",
requestBody: requestBody,
view: view,
completionHandler: { (response : ApiContainer<Client>?, error : Error?) in
if let error = error {
print("error calling POST on /todos")
print(error)
return
}
let b = (response?.meta)!
let a = (response?.result[0])
let client_id = a?.client_id
self.client?.client_id = client_id

if(b.sucess == "yes") {

//change message and use the custom func like on error.
let alert = UIAlertController(title: "Success!", message: "All good", preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {
(_)in
self.performSegue(withIdentifier: "unwindToClients", sender: self)
})

alert.addAction(OKAction)
DispatchQueue.main.async(execute: {
self.present(alert, animated: true, completion: nil)
})


}
else
{
self.showAlert(title: "Error", message: "Error Creating Client")
//return
}
} )
}


override func viewDidLoad() {
super.viewDidLoad()
tableView.sectionHeaderHeight = 50.0;

navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Save", style: .plain, target: self, action: #selector(save))


let thePicker = UIPickerView()
provinceTextField.inputView = thePicker
thePicker.delegate = self

// ToolBar
let toolBar = UIToolbar()
toolBar.barStyle = .default
toolBar.isTranslucent = true
toolBar.tintColor = UIColor(red: 92/255, green: 216/255, blue: 255/255, alpha: 1)
toolBar.sizeToFit()

// Adding Button ToolBar
let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(ClientDetailViewController.doneClick))
let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(ClientDetailViewController.cancelClick))
toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
provinceTextField.inputAccessoryView = toolBar

}

@objc func doneClick() {
provinceTextField.resignFirstResponder()
}
@objc func cancelClick() {
provinceTextField.resignFirstResponder()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var rows: Int = 0
if section < numberOfRowsAtSection.count {
rows = numberOfRowsAtSection[section]
}
return rows
}



override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let backItem = UIBarButtonItem()
backItem.title = "Client"
navigationItem.backBarButtonItem = backItem

if segue.identifier == "unwindToClients",
let destination = segue.destination as? ClientsViewController
{
destination.client = client
}

if segue.identifier == "showContacts",
let destination = segue.destination as? ContactsViewController
{
destination.client = client
}

}


// MARK: - Picker view
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}

func pickerView( _ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return provinces.count
}

func pickerView( _ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return provinces[row].name
}

func pickerView( _ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
provinceTextField.text = provinces[row].name
}




}




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()
}

}

最佳答案

  1. 将数据源中的项目附加到要在表中插入行的索引处。而不是按照步骤 2、3、4 进行操作。

  2. 调用方法tbl.beginupdate

  3. 调用table view的insertRowsAtIndexPaths方法
  4. 调用 tbl.endupdate

关于ios - Swift - 在 TableView 的某个部分中更新或插入一行,而无需重新加载所有数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48575878/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com