Reputation: 255
I have an app with a chain of TableViewControllers, linked by a notification controller, retrieving information from a webservice. Data from the next table is pulled from an webservice, regarding the data chosen on the previous one. 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. 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. 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...
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.
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.
When a client is selected it segues to the next TableViewController, passing a client_id between the ViewControllers.
Here's a code sample from the 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'
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. 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'
As you guys can see, it is trying to do it on the ProjectsViewController, which was already dismissed, by the backButton.
Any ideas?
Upvotes: 1
Views: 583
Reputation: 6176
I tried and it works for me. 2 viewcontrollers, each with a different data source, a "toSecondVC" segue between the two.
The 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 :
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
}
}
Upvotes: 1