#ios #swift
#iOS #swift
Вопрос:
Я впервые использую swift или Xcode.
Я пытаюсь создать простое приложение для регистрации транзакций
В первом представлении есть таблица, в которой каждая строка представляет учетную запись и ее баланс. Когда вы нажимаете на строку, открывается второе представление через segue, которое содержит таблицу всех транзакций для этой учетной записи. В верхней части этого представления есть кнопка «Добавить транзакцию», которая открывает третье представление, в котором есть форма и кнопка «Добавить». При нажатии кнопки «Добавить» я использую .reloadData() для таблицы во втором представлении, а третье представление отклоняется. Но, визуально, в таблице нет дополнительной строки. Это связано с тем, что после закрытия 3-го представления недавно добавленная транзакция больше не находится в массиве транзакций.
Я делаю что-то не так? Моя попытка и изображения приведены ниже.
Первый просмотр
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 ""
}
Комментарии:
1. Взгляните на эту статью: learnappmaking.com /… . Если вы прокрутите вниз, он охватывает обратную передачу данных с дочернего контроллера представления на родительский контроллер представления.
Ответ №1:
Проблема в том, что вы добавляете новый 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()
}
Затем, когда вы выполняете переход к переходу от 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
, сохраните на устройстве, обновите базу данных и т.д.