Swift:我的委托协议方法需要在另一个视图控制器上执行

Posted

技术标签:

【中文标题】Swift:我的委托协议方法需要在另一个视图控制器上执行【英文标题】:Swift: My Delegate Protocol Methods Need to Execute on Another View Controller 【发布时间】:2014-12-27 19:27:50 【问题描述】:

这是一个非常令人困惑的问题,所以我会尽力解释它。

我有视图控制器 A、B、C、D 和 E

我不确定我说的对不对,但换个说法,E 需要与 A 交谈,但 A 和 E 之间没有任何转义来设置委托。

A > B > C > D > E > A

有人告诉我,当您在 swift 中使用委托来访问视图控制器之间的数据时,您必须准备好很多东西:

    为对象 B 定义一个委托协议。 给对象 B 一个可选的委托变量。这个变量应该很弱。 让对象 B 在感兴趣时向其委托发送消息 发生,例如用户按下取消或完成按钮,或者当它 需要一条信息。 使对象 A 符合委托协议。它应该把名字 类行中的协议并实现协议中的方法。 告诉对象 B 对象 A 现在是它的代表。

我一直在使用 prepapreforsegue 在视图控制器之间传递一个对象,因为它们从一个导航到下一个,并在它们继续通过 prepareforsegue 方法时添加到它。

在最终的视图控制器上,我有协议方法,这些方法旨在执行第一个视图控制器,但因为最后一个视图控制器与不同的视图控制器分离。问题是它应该在第一个视图控制器上执行这些方法。如果第一个视图控制器不能告诉最后一个视图控制器它是 segue,它怎么能到达它。

这里有一些简单的代码来告诉你我的问题和我的意思。

第一:

import UIKit

class FirstViewController: UITableViewController, 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 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


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)


下一个:

import UIKit


class Next1ViewController: UITableViewController, 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 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 Next2ViewController
    controller.entry = entry




接下来 2:

import UIKit


class Next2ViewController: UITableViewController, 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 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 = ???? //Not self, but needs to be the first one.
    



最后:

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()


...


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


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



【问题讨论】:

能否修改NextViewController 中的prepareForSegue 代码以设置controller.delegate = self.delegate?因为 self.delegate 引用了 FirstViewController,所以应该在 FirstViewController 上调用方法。 @pbasdf 我想我在您输入此评论时输入了我的答案!那时我们可能肯定是对的。 @jrturton 我认为它会起作用,但是对于 5 个 VC,你建议使用通知可能是更好的做法。 真的吗?等一下再看一遍帖子,希望我编辑它以减少混乱。唯一需要就位的代表是在第一个和最后一个之间,而不是在第一个和第二个或第二个和第三个之间。不确定这是否重要。 在我的答案中添加了一个部分进行解释。如果中间 vc 对委托没有用处,请使用通知。 【参考方案1】:

你不能让你的第一个视图控制器符合所有的委托协议(或者,可能,制作一个单一的委托协议,否则你会遇到转换问题),然后不要这样做:

controller.delegate = self

做事

controller.delegate = self.delegate

或者,如果您已经删除了几个步骤,则使用通知通常比委派更好。如果中间的视图控制器除了转发之外没有其他目的,您应该使用通知。

【讨论】:

是的,这行不通,我试过了。这只有在实际上只有 3 个视图控制器时才有效,这只是一个示例,但我会在帖子中修复它,因为这很令人困惑,抱歉。还有更多。有第一,第二,第三,第四,第五,最后。 在这种情况下,一定要使用通知。 我将不得不查找通知,我不确定在这种情况下这些是什么,但是谢谢,如果这有效,我会告诉你。 是的,我在通知中找不到任何内容,我不明白你的意思。我听说过通知的唯一上下文是推送通知。 @Sephethus 我今天也遇到了这个问题...发现这个 SO 问题,最后一个答案对 NSNotificationCenter 有很大帮助...***.com/questions/24049020/…

以上是关于Swift:我的委托协议方法需要在另一个视图控制器上执行的主要内容,如果未能解决你的问题,请参考以下文章

UIView 类中的 Swift 集合视图委托

Swift BarButtonItem 不更新

Swift 中不调用协议委托方法

UIPageViewController 不调用委托方法(Swift 5)

XIB 和视图控制器之间的协议委托

如何将我的视图控制器设置为它自己的委托?