Доступ к предыдущему элементу viewController с его тегом

В моем сценарии мне нужно получить доступ к кнопке с определенным тегом из предыдущего viewController, если эта кнопка существует. Эта кнопка будет расположена в повторно используемой ячейке табличного представления.

Я хочу изменить текст этой кнопки из текущего представления. Я думал об отправке данных с помощью NotificationCenter, но может быть несколько viewController, которые переходили к текущему представлению, поэтому это был не очень хороший способ.

Пробовал с одним

override func didMove(toParentViewController parent: UIViewController?) {
    super.didMove(toParentViewController: parent)

    if parent == self.navigationController?.parent {
        //check if previous viewController has the button and access it    
    }
}

Любая помощь?


person Utku Dalmaz    schedule 01.10.2018    source источник
comment
Рассматривали ли вы реализацию prepareForSegue и передачу этой кнопки в этот метод?   -  person efimovdk    schedule 01.10.2018
comment
Я уже использую prepareForSegue. Можете ли вы показать мне, как использовать переданную кнопку в текущем представлении?   -  person Utku Dalmaz    schedule 01.10.2018
comment
@UtkuDalmaz это именно то, что делает опубликованный ответ, за исключением того, что он не использует логику раскадровки. Я знаю, почему за него сильно проголосовали, когда единственный ответивший парень ошибся в своей первой строке и предложил решение, связанное с изменением вашей архитектуры. Вы поняли опубликованный ответ?   -  person Rakesha Shastri    schedule 01.10.2018
comment
@RakeshaShastri да, я понял. но я не знаю почему так много минусов   -  person Utku Dalmaz    schedule 01.10.2018
comment
@UtkuDalmaz ты тогда пробовал?   -  person Rakesha Shastri    schedule 01.10.2018
comment
Я собирался попробовать, но отрицательные голоса заставили меня остановиться. есть ли другой способ добиться этого кстати?   -  person Utku Dalmaz    schedule 01.10.2018
comment
@UtkuDalmaz даже я хотел бы знать, есть ли лучший способ. Поэтому я просто оставлю свой ответ для кого-то, кто объяснит мне, почему это неправильно.   -  person Rakesha Shastri    schedule 01.10.2018
comment
Что означает ваша кнопка? Какое-то государство?   -  person FruitAddict    schedule 01.10.2018
comment
@FruitAddict это кнопка подписки. пользователь может следить за другим пользователем с помощью этой кнопки. Но вместо этого они также могут перейти к профилю пользователя и следить за ним, но мне нужно изменить эту кнопку, когда пользователь следит за просмотром профиля. это моя проблема.   -  person Utku Dalmaz    schedule 01.10.2018
comment
позвольте мне опубликовать мой ответ   -  person FruitAddict    schedule 01.10.2018
comment
@UtkuDalmaz Я думаю, что проблема заключалась в том, что я напрямую сохранил и получил доступ к свойству контроллера представления вместо использования протоколов. Самый последний ответ был бы лучшей версией моего ответа, который, в конце концов, делает то же самое, но чище.   -  person Rakesha Shastri    schedule 01.10.2018


Ответы (1)


(этот ответ не об архитектуре приложения, а просто публикует простое решение проблемы автора)

Вы говорите, что ваша кнопка представляет состояние «следить» за вашей моделью (профиль). Вы, вероятно, хотите иметь модель, которая будет представлять профиль:

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
comment
Омг, думаю, я выберу способ viewDidAppear :) спасибо за информацию. - person Utku Dalmaz; 01.10.2018
comment
Да, делегирование — это более «ясный» способ ведения дел, но для простых случаев использования вы можете просто перезагрузить все в зависимости от состояния. Важная вещь из моего поста, подождите, позвольте мне обновить пост - person FruitAddict; 01.10.2018
comment
Я применил способ протокола, и он отлично работает. Спасибо - person Utku Dalmaz; 01.10.2018