简体   繁体   English

iOS Swift-协议将委托发送到错误的TableViewController

[英]iOS Swift - Protocol sending delegate to wrong TableViewController

I have an app with a chain of TableViewControllers, linked by a notification controller, retrieving information from a webservice. 我有一个带有TableViewControllers链的应用程序,该链表由通知控制器链接,从Web服务中检索信息。 Data from the next table is pulled from an webservice, regarding the data chosen on the previous one. 与上一个表中选择的数据有关,来自下一个表的数据是从Web服务中提取的。 When I pull any table to refresh, it requests again the information a protocol sends a delegate message to the tableview to refresh the information. 当我拉出任何表进行刷新时,它再次请求信息,而协议将委托消息发送到表视图以刷新信息。

Well, so far so good. 好吧,到目前为止一切都很好。 But, I'm experiencing something strange... Example: I'm on tableView #2 and then use the navigation back button to get to the previous table, the #1. 但是,我遇到了一些奇怪的事情……例如:我在tableView#2上,然后使用导航后退按钮转到上一张表#1。 When, on #1, I pull the tableview to refresh, it crashes and gives me one of those "unrecognized selector sent to instance" telling that Tableview #2 doesn't have the optional delegate method, used to get the information to fill TableView #1. 当在#1上,我拉动tableview刷新时,它崩溃并给我一个“无法识别的选择器发送到实例”的信息,告诉我Tableview#2没有可选的委托方法,该方法用于获取信息以填充TableView #1。 And I'm not even on TableView #2 anymore, iOS is sending the delegate message to the wrong ViewController, as the tableViewController wasn't even dismissed when the NavigationController backButton was clicked... 而且我什至不在TableView#2上,iOS正在将委托消息发送到错误的ViewController,因为单击NavigationController backButton时甚至没有关闭tableViewController……

Has anyone experienced it? 有没有人经历过? I know it seems a little bit confuse, but it is what's happening. 我知道这似乎有点混乱,但这是正在发生的事情。

Lets get some code in here: Two TableViewControllers: ClientsViewController and ProjectsViewController When you select a client on the ClientsViewController Table, it loads all projects from the client on the ProjectsViewController Table. 让我们在这里获取一些代码:两个TableViewControllers:ClientsViewController和ProjectsViewController当您在ClientsViewController Table上选择一个客户端时,它将在ProjectsViewController Table上从该客户端加载所有项目。

ClientsViewController ClientsViewController

override func viewDidLoad() {
        super.viewDidLoad()
        wsCommHandler.delegate = self
        self.tableView.delegate = self
        self.tableView.dataSource = self

        self.refreshControl!.addTarget(self, action: Selector("refreshClients:"), forControlEvents: UIControlEvents.ValueChanged)
        wsCommHandler.getClients()

    }

    func refreshClients(sender:AnyObject){
        println("Refreshing")
        self.refreshControl?.beginRefreshing()
        wsCommHandler.getClients()
        self.refreshControl?.endRefreshing()
    }

func didReceiceResponseFromGetClientsRequest(response: [AnyObject]) {
        self.clients = response
        self.tableView.reloadData()

    }

The wsCommHandler 'getClients()' retrieves from a webservice all the clients and uses a delegate 'didReceiceResponseFromGetClientsRequest' to reload the table. wsCommHandler'getClients()'从Web服务检索所有客户端,并使用委托'didReceiceResponseFromGetClientsRequest'重新加载表。

When a client is selected it segues to the next TableViewController, passing a client_id between the ViewControllers. 选择一个客户端后,它将选择到下一个TableViewController,在ViewController之间传递client_id。

Here's a code sample from the ProjectsViewController 这是ProjectsViewController中的代码示例

override func viewDidLoad() {
        super.viewDidLoad()
        wsCommHandler.delegate = self
        self.tableView.delegate = self
        self.tableView.dataSource = self

        self.refreshControl!.addTarget(self, action: Selector("refreshProjects:"), forControlEvents: UIControlEvents.ValueChanged)
        wsCommHandler.getProjectsByClient(client_id) 
    }

    func refreshProjects(sender:AnyObject){
        println("Refreshing")
        self.refreshControl?.beginRefreshing()
        wsCommHandler.getProjectsByClient(client_id)
        self.refreshControl?.endRefreshing()
    }

    func didReceiceResponseFromGetProjectsRequest(response: [AnyObject]) {
        self.projects = response
        self.tableView.reloadData()

    }

It loads the Projects on the screen on the same way as the clients, but now using the delegate 'didReceiceResponseFromGetProjectsRequest' 它以与客户端相同的方式将项目加载到屏幕上,但是现在使用委托'didReceiceResponseFromGetProjectsRequest'

Now, if I press the navigation controller back button, it brings the ClientsViewController back to front (without reloading it)... When I pull it to refresh. 现在,如果我按下导航控制器的后退按钮,它将把ClientsViewController放回到前面(无需重新加载)...当我拉动它进行刷新时。 The class is called, retrieves the data and then: Crash! 调用该类,检索数据,然后:崩溃!

2015-03-06 09:26:18.978 PostItHours[9174:792018] -[PostItHours.ProjectsViewController didReceiceResponseFromGetClientsRequest:]: unrecognized selector sent to instance 0x7fe0c4132c30 2015-03-06 09:26:18.980 PostItHours[9174:792018] Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[PostItHours.ProjectsViewController didReceiceResponseFromGetClientsRequest:]: unrecognized selector sent to instance 0x7fe0c4132c30' 2015-03-06 09:26:18.978 PostItHours [9174:792018]-[PostItHours.ProjectsViewController didReceiceResponseFromGetClientsRequest:]:无法识别的选择器已发送到实例0x7fe0c4132c30 2015-03-06 09:26:18.980 PostItHours [9174:792018]终止应用程序到期到未捕获的异常“ NSInvalidArgumentException”,原因:“-[PostItHours.ProjectsViewController didReceiceResponseFromGetClientsRequest:]:无法识别的选择器已发送到实例0x7fe0c4132c30”

As you guys can see, it is trying to do it on the ProjectsViewController, which was already dismissed, by the backButton. 如你们所见,它正在尝试通过backButton在已经关闭的ProjectsViewController上执行此操作。

Any ideas? 有任何想法吗?

I tried and it works for me. 我尝试了,对我有用。 2 viewcontrollers, each with a different data source, a "toSecondVC" segue between the two. 2个视图控制器,每个都有不同的数据源,两者之间有一个“ toSecondVC”序列。

The ViewController : ViewController:

import UIKit

class ViewController: UITableViewController {
    var texts = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()
        texts.append("viewController")
        self.title = "viewController"
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        refreshControl = UIRefreshControl()
        refreshControl!.addTarget(self,
            action: "handleRefresh:",
            forControlEvents: .ValueChanged)

        tableView.addSubview(refreshControl!)

    }

    func handleRefresh(paramSender: AnyObject){
        //pause it 1 sec
        let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(NSEC_PER_SEC))
        dispatch_after(popTime,
            dispatch_get_main_queue(), {
                self.texts.append(String("viewController-\(self.texts.count+1)"))
                self.refreshControl!.endRefreshing()
                let indexPathOfNewRow = NSIndexPath(forRow: self.texts.count - 1,
                    inSection: 0)

                self.tableView!.insertRowsAtIndexPaths([indexPathOfNewRow],
                    withRowAnimation: .Automatic)
        })
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "toSecondVC" {
            let viewController:SecondVC = segue.destinationViewController as SecondVC
            let indexPath = self.tableView.indexPathForSelectedRow()
            viewController.stringSelected = texts[indexPath!.row]
        }
    }

    //MARK : TableView Delegate
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
        cell.textLabel.text = texts[indexPath.row]
        return cell
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return texts.count
    }
}

The secondVC : 第二个VC:

import UIKit

class SecondVC: UITableViewController {
    var texts = [String]()
    var stringSelected = String()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "secondVC"
        texts.append("secondVC")
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        refreshControl = UIRefreshControl()
        refreshControl!.addTarget(self,
            action: "handleRefresh:",
            forControlEvents: .ValueChanged)

        tableView.addSubview(refreshControl!)

        println("stringSelected : \(stringSelected)")
    }

    func handleRefresh(paramSender: AnyObject){

        //pause it 1 sec
        let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(NSEC_PER_SEC))
        dispatch_after(popTime,
            dispatch_get_main_queue(), {
                self.texts.append(String("secondVC-\(self.texts.count+1)"))
                self.refreshControl!.endRefreshing()
                let indexPathOfNewRow = NSIndexPath(forRow: self.texts.count - 1,
                    inSection: 0)

                self.tableView!.insertRowsAtIndexPaths([indexPathOfNewRow],
                    withRowAnimation: .Automatic)

        })

    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
        cell.textLabel.text = texts[indexPath.row]
        return cell
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return texts.count
    }


}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM