ios - 从孙子视图控制器进行操作 - Swift Xcode
问题描述
这是我第一次使用 swift 或 Xcode。
我正在尝试制作一个简单的交易注册应用程序
第一个视图有一个表格,其中每一行代表一个帐户,它是余额。当您单击一行时,它会通过 segue 打开第二个视图,其中包含该帐户所有交易的表格。在这个视图的顶部有一个“添加事务”按钮,它打开了第三个视图,它有一个表单和一个“添加”按钮。当按下“添加”按钮时,我在第二个视图中的表上使用 .reloadData() 并关闭第三个视图。但是,从视觉上看,该表中没有额外的行。这是因为在第三个视图关闭后,新添加的事务不再在事务数组中。
难道我做错了什么?我的尝试和图像如下。
第一视角
import UIKit
class AccountsViewController: UIViewController {
@IBOutlet weak var newAccountNameUITextField: UITextField!
@IBOutlet weak var newAccountBalanceUITextField: UITextField!
@IBOutlet weak var addNewAccountUIButton: UIButton!
@IBOutlet weak var accountsUITableView: UITableView!
var selectedAccount: Account = Account(name: "", balance: "")
var accounts = [Account(name: "PNC", balance: "45.93")]
override func viewDidLoad() {
super.viewDidLoad()
accountsUITableView.delegate = self
accountsUITableView.dataSource = self
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let transactionsViewController = segue.destination as? TransactionsViewController {
transactionsViewController.modalPresentationStyle = .fullScreen
transactionsViewController.account = selectedAccount
}
}
}
extension AccountsViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedAccount = accounts[indexPath.row]
performSegue(withIdentifier: "trasactionsSegue", sender: self)
}
}
extension AccountsViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return accounts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "account", for: indexPath) as! AccountCell
cell.selectionStyle = .none
cell.nameUILabel?.text = accounts[indexPath.row].name
cell.balanceUILabel?.text = accounts[indexPath.row].balance
return cell
}
}
第二视图
import UIKit
class TransactionsViewController: UIViewController {
@IBOutlet weak var nameUILabel: UILabel!
@IBOutlet weak var TransactionsUITableView: UITableView!
@IBOutlet weak var balanceUILabel: UILabel!
var account: Account = Account(name: "", balance: "", transactions: [])
override func viewDidLoad() {
super.viewDidLoad()
TransactionsUITableView.dataSource = self
nameUILabel.text = account.name
balanceUILabel.text = account.balance
}
//Pass data to newTransactionViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let newTransactionViewController = segue.destination as? NewTransactionViewController {
newTransactionViewController.account = account
}
}
//Dismiss this view when Accounts button is pressed
@IBAction func backToAccountsTouchUpInside(_ sender: UIButton) {
self.dismiss(animated: true, completion: {
self.presentingViewController?.dismiss(animated: true, completion: nil)
})
}
@IBAction func addTransactionTouchUpInside(_ sender: UIButton) {
performSegue(withIdentifier: "addTransactionSegue", sender: self)
}
@IBAction func unwindToViewControllerA(segue: UIStoryboardSegue) {
DispatchQueue.global(qos: .userInitiated).async {
DispatchQueue.main.async {
//At this point the newly added transaction is missing
self.TransactionsUITableView.reloadData()
}
}
}
}
extension TransactionsViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return account.transactions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "transaction", for: indexPath) as! TransactionCell
cell.selectionStyle = .none
cell.descriptionUILabel.text = account.transactions[indexPath.row].description
cell.amountUILabel.text = account.transactions[indexPath.row].amount
cell.balanceUILabel.text = account.transactions[indexPath.row].balanceAfterAmount
return cell
}
}
第三视图
import UIKit
class NewTransactionViewController: UIViewController {
@IBOutlet weak var clearedUISegmentedControl: UISegmentedControl!
@IBOutlet weak var depositingUISegmentedControl: UISegmentedControl!
@IBOutlet weak var descriptionUITextField: UITextField!
@IBOutlet weak var amountUITextField: UITextField!
@IBOutlet weak var addTransactionUIButton: UIButton!
var account: Account? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func addTransactionTouchUpInside(_ sender: UIButton) {
let depositing = depositingUISegmentedControl.selectedSegmentIndex == 0 ? true : false
let cleared = clearedUISegmentedControl.selectedSegmentIndex == 0 ? true : false
let description = descriptionUITextField.text
let amount = amountUITextField.text
let balanceAfterAmount = operationOnCurrency(depositing: depositing, amount: amount!, balance: account!.balance)
let newTransaction = Transaction(depositing: depositing, amount: amount!, balanceAfterAmount: balanceAfterAmount, description: description!, cleared: cleared)
account?.transactions.append(newTransaction)
self.performSegue(withIdentifier: "backToTransactions", sender: self)
}
}
func operationOnCurrency (depositing: Bool, amount: String, balance: String) -> String {
//Return empty string for now
return ""
}
解决方案
问题是您在 中创建Transaction
的Account
实例中追加一个新的,而不是更新由或 中的根数据源NewTransactionViewController
持有的实例中的数据(假设是根数据源)。按下添加按钮时,您需要向后传递更新的数据。您可以创建一个委托协议来处理这个问题。使用从到示例的转换,首先创建协议:TransactionsViewController
AccountsViewController
NewTransactionViewController
TransactionsViewController
protocol NewTransactionDelegate {
func transactionAddedToAccount(account: Account)
}
然后在您的内部,您NewTransactionViewController
将要创建一个委托属性:
class NewTransactionViewController: UIViewController {
@IBOutlet weak var clearedUISegmentedControl: UISegmentedControl!
@IBOutlet weak var depositingUISegmentedControl: UISegmentedControl!
@IBOutlet weak var descriptionUITextField: UITextField!
@IBOutlet weak var amountUITextField: UITextField!
@IBOutlet weak var addTransactionUIButton: UIButton!
var account: Account? = nil
**var delegate: NewTransactionDelegate?**
override func viewDidLoad() {
super.viewDidLoad()
}
在您的addTransactionTouchUpInside
方法内部调用委托方法:
@IBAction func addTransactionTouchUpInside(_ sender: UIButton) {
let depositing = depositingUISegmentedControl.selectedSegmentIndex == 0 ? true : false
let cleared = clearedUISegmentedControl.selectedSegmentIndex == 0 ? true : false
let description = descriptionUITextField.text
let amount = amountUITextField.text
let balanceAfterAmount = operationOnCurrency(depositing: depositing, amount: amount!, balance: account!.balance)
let newTransaction = Transaction(depositing: depositing, amount: amount!, balanceAfterAmount: balanceAfterAmount, description: description!, cleared: cleared)
account?.transactions.append(newTransaction)
**delegate?.transactionAddedToAccount(account: account)**
self.performSegue(withIdentifier: "backToTransactions", sender: self)
}
现在回到你,TransactionsViewController
你会想要遵守NewTransactionDelegate
协议并实现协议中声明的所需方法:
class TransactionsViewController: UIViewController, NewTransactionDelegate {
func transactionAddedToAccount(account: Account) {
self.account = account
tableView.reloadData()
}
然后,当您执行 segue 以从 to 转换时TransactionsViewController
,NewTransactionViewController
您需要将目标视图控制器的委托属性设置为 self:
//Pass data to newTransactionViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let newTransactionViewController = segue.destination as? NewTransactionViewController {
**newTransactionViewController.delegate = self**
newTransactionViewController.account = account
}
}
现在,当点击添加按钮时,会调用委托方法并传递 的新实例account
,然后将其传递回前一个视图控制器并更新。
请注意,这只会在帐户实例中更新,TransactionsViewController
并且您还需要在源更新此帐户的数据,否则在解除分配时它将丢失TransactionsViewController
。将新帐户传回AccountsViewController
,保存到设备,更新数据库等。
推荐阅读
- java - 使用 Java 中的加载类导入属性文件时出错
- python - Python Pexpect 期望得到超时错误
- next.js - Next.js 忽略 NODE_ENV=development
- azure-devops - YAML CI 正在扁平化文件结构
- conda - conda 安装在测试环境中
- couchbase - 在 Couchbae 中选择动态键的 N1QL 查询
- r - 通过 knitr 将 R sweave 文件编译为 pdf 时,\includegraphics{} 命令放错了位置
- file-upload - 在 Web 应用程序上存储上传文档的最佳方式
- javascript - 如何使用 IntersectionObserver 制作无限滚动条,使其不会触底?
- c# - 使用 EF 播种数据