使用其标签访问先前的viewController元素

时间:2018-10-01 12:28:44

标签: ios swift segue

在我的场景中,如果该按钮存在,则需要从以前的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    
    }
}

有帮助吗?

1 个答案:

答案 0 :(得分:0)

(此答案与应用程序体系结构无关,只是发布针对作者问题的简单解决方案)

您说您的按钮代表模型(“个人资料”)的“关注”状态。您可能想要一个可以代表配置文件的模型:

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回到顶部时,整个表将重新加载。

这里最重要的是使UI(用户界面)与状态(模型等)分开。 UI应该根据状态呈现/更新自身,并且除了传递“单击i,请处理”之外,不应处理任何业务逻辑。