(этот ответ не об архитектуре приложения, а просто публикует простое решение проблемы автора)
Вы говорите, что ваша кнопка представляет состояние «следить» за вашей моделью (профиль). Вы, вероятно, хотите иметь модель, которая будет представлять профиль:
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)
}
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
}
Сама ячейка может выглядеть так:
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
снова становится главным контроллером.
Самое главное здесь — отделить пользовательский интерфейс (пользовательский интерфейс) от состояния (моделей и т. д.). Пользовательский интерфейс должен отображать/обновлять себя в зависимости от состояния и не должен обрабатывать какую-либо бизнес-логику, кроме передачи «я был нажат, пожалуйста, обработайте это» в логику.
person
FruitAddict
schedule
01.10.2018