(этот ответ не об архитектуре приложения, а просто о простом решении проблемы автора)
Вы говорите, что ваша кнопка представляет состояние отслеживания вашей модели (профиля).Вы, вероятно, хотите иметь модель, которая будет представлять профиль:
class Profile {
var following : Bool = false
}
Ваш первый ViewController
, вероятно, будет выглядеть следующим образом:
class ProfileListViewController : UIViewController, ProfileDetailsViewControllerDelegate {
var profiles : [Profile] = [...]
func userDidChangeProfileInfo(_ profile : Profile)() {
(...)
}
}
Когда вы откроете профиль, вы позвонитечто-то вроде этого в вашем ProfileListViewController
:
func openProfileDetails(at indexPath: IndexPath) {
let profile = profiles[indexPath.row]
let detailsViewController = ProfileDetailsViewController.getInstance()
detailsViewController.profile = profile
detailsViewController.delegate = self
self.navigationController?.pushViewController(detailsViewController, animated: true)
}
поле delegate
- это протокол, который может выглядеть следующим образом и реализованный в приведенном выше коде:
protocol ProfileDetailsViewControllerDelegate : class {
func userDidChangeProfileInfo(_ profile : Profile)
}
The ProfileDetailsViewController
:
class ProfileDetailsViewController : UIViewController {
var profile: Profile?
weak var delegate : ProfileDetailsViewControllerDelegate?
func didTapFollowButton() {
profile.following = true
delegate?.userDidChangeProfileInfo(profile)
}
}
обратно в ваш ProfileListViewController
, будет вызван метод delegate
, и вы можете перезагрузить строки (или весь просмотр таблицы, если хотите):
func userDidChangeProfileInfo(_ profile : Profile)() {
if let row = profiles.firstIndex(where: { $0 == profile }) {
tableView.reloadRows(at: [IndexPath(row: row, section: 0)], with: .automatic)
}
}
Далее ячейка будет воссоздана с этим индексом, поэтому будет вызван метод cellForRowAt
.Вы можете снова настроить ячейку на основе изменений в вашей модели (изменить текст, стиль, вернуть другую ячейку и т. Д., Независимо от того, плавает ли ваша лодка и подходит ли она для ваших случаев использования):
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(...)
let profile = profiles[indexPath.row]
if profile.following {
cell.type = .following
} else {
cell.type = .notFollowing
}
return cell
}
Сама ячейка может выглядеть следующим образомthis:
enum ProfileTableCellMode {
case following
case notFollowing
}
class ProfileTableCell : UITableViewCell {
@IBOutlet weak var followButton : UIButton!
var state: ProfileTableCellMode = .notFollowing { //default value
didSet {
onStateUpdated()
}
}
func onStateUpdated() {
switch state {
case .following:
followButton.setTitle("Unfollow", for: .normal)
case .notFollowing:
followButton.setTitle("Follow", for: .normal)
}
}
}
Вы также можете пропустить все делегирующие вещи и просто сделать что-то подобное в ProfileListViewController
:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.tableView.reloadData()
}
Таким образом, вся таблица перезагружается, когда ProfileListViewController
снова стал верхним контроллером.
Самое важное здесь - это отделить пользовательский интерфейс (пользовательский интерфейс) от состояния (модели и т. Д.).Пользовательский интерфейс должен отображать / обновлять себя в зависимости от состояния и не должен обрабатывать какую-либо бизнес-логику, кроме передачи «я нажал, пожалуйста, обработайте это» логике.