samedi 27 décembre 2014

Swift: Why does my Protocol Method Execute on the Wrong View Controller?

This is a really confusing problem so I will try to explain it as best as I can.


I have view controllers A, B, C, D and E


B needs to be a delegate with A and E needs to be a delegate of A and D.


I'm not sure if I said that right, but to rephrase that, A needs to talk to E and so does D.


I was told that when you use delegates in swift to access data between view controllers, you have to have a number of things in place:



  1. Define a delegate protocol for object B.

  2. Give object B an optional delegate variable. This variable should be weak.

  3. Make object B send messages to its delegate when something interesting happens, such as the user pressing the Cancel or Done buttons, or when it needs a piece of information.

  4. Make object A conform to the delegate protocol. It should put the name of the protocol in its class line and implement the methods from the protocol.

  5. Tell object B that object A is now its delegate.


I have been using delegates to pass an object between view controllers as they navigate from one to the next, adding to it as they continue through the prepareforsegue method.


I have to set up protocol methods, but I've been leaving the protocol section empty because there's nothing to execute. I just need access to pass the object.


On the final view controller, I have protocol methods that are meant to be executed the first view controller, but because the last view controller is already a delegate of the second to last view controller, I have to put the methods there as well. Problem is it's supposed to execute those methods on the first view controller, not the second to last.


Here is some simple code to show you my problem and what I mean.


First:



import UIKit

class FirstViewController: UITableViewController, NextViewControllerDelegate, LastViewControllerDelegate {

var entry: EntryItem!

override func viewDidLoad() {
super.viewDidLoad()
entry = EntryItem()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false

// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 0
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return 0
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as UITableViewCell

// Configure the cell...

return cell
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

//here's where I access the next view controller and set controller.entry and controller.delegate
let controller = segue.destinationViewController as NextViewController
controller.entry = entry
controller.delegate = self
}

func lastViewControllerDidCancel(controller: LastViewController, didNotFinishAddingEntry draftentry: EntryItem){
//this is where I wanna do something
dismissViewControllerAnimated(true, completion: nil)
}
func lastViewController(controller: LastViewController, didFinishAddingEntry finalentry: EntryItem){
//this is where I wanna do something
dismissViewControllerAnimated(true, completion: nil)
}
}


Next:



import UIKit

protocol NextViewControllerDelegate: class {

}

class NextViewController: UITableViewController, LastViewControllerDelegate {

weak var delegate: NextViewControllerDelegate?
var entry: EntryItem!

override func viewDidLoad() {
super.viewDidLoad()

// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false

// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 0
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return 0
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as UITableViewCell

// Configure the cell...

return cell
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//here's where I access the next view controller and set controller.entry and controller.delegate
let controller = segue.destinationViewController as LastViewController
controller.entry = entry
controller.delegate = self
}

func lastViewControllerDidCancel(controller: LastViewController, didNotFinishAddingEntry draftentry: EntryItem){
//do nothing here because this isn't where I want these executed
}
func lastViewController(controller: LastViewController, didFinishAddingEntry finalentry: EntryItem){
//do nothing here because this isn't where I want these executed
}

}


Last:



import UIKit

protocol LastViewControllerDelegate: class {
func lastViewControllerDidCancel(controller: LastViewController, didNotFinishAddingEntry draftentry: EntryItem)
func lastViewController(controller: LastViewController, didFinishAddingEntry finalentry: EntryItem)
}

class LastViewController: UITableViewController {

weak var delegate: LastViewControllerDelegate?
var entry: EntryItem!

override func viewDidLoad() {
super.viewDidLoad()

// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false

// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 0
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return 0
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as UITableViewCell

// Configure the cell...

return cell
}

@IBAction func cancel(){
delegate?.lastViewControllerDidCancel(self, didNotFinishAddingEntry: entry)
}

@IBAction func done(){
//do some final additions to entry object
delegate?.lastViewController(self, didFinishAddingEntry: entry)
}

}


As you can see, the protocol methods set on the LastViewController are trying to execute on the NextViewController, not the FirstViewController. The problem is it wont let me leave them out of the NextViewController.




Aucun commentaire:

Enregistrer un commentaire