【问题标题】:Passing data with protocols without going back to original controller使用协议传递数据而不返回原始控制器
【发布时间】:2016-10-23 16:26:29
【问题描述】:

我一直在研究委托的工作方式。您在控制器 A 中定义协议,创建委托变量,并通过委托调用函数。然后,在控制器 B 中,遵循协议,实现方法,然后使用 prepareForSegue 告诉控制器 A,控制器 B 是委托。

但这涉及到A -> B -> A。我需要知道如何做A -> B。我一直在尝试通过以下代码来做到这一点:

在控制器 A 中声明协议

protocol CellDataDelegate {

    func userDidTapCell(data: String)
}

在A中创建一个委托变量

var cellDelegate: CellDataDelegate? = nil

点击单元格时调用 A 中委托中的函数

if cellDelegate != nil {

    let cellKey = keys[indexPath.row].cellKey
    cellDelegate?.userDidTapCell(data: cellKey)

    self.performSegue(withIdentifier: "showDetails", sender: self)
}

将委托添加到控制器B并符合方法

class DetailsVC: UIViewController, CellDataDelegate

功能:

func userDidTapCell(data: String) {

    useData(cellKey: data)
}

这里的问题是委托过程的最后一部分。我不能使用 prepareForSegue 来执行 controllerA.delegate = self 部分,因为我不想回到控制器 A,我需要留在控制器 B。那么我如何告诉控制器 A B 是委托?

【问题讨论】:

  • 我不明白这里的委托与 segue 有什么关系。执行的转场是在界面构建器中设置的转场,您为转场做的准备不会影响您最终进入哪个视图控制器?我是否误解了您要做什么?
  • 你能更清楚地解释你想要做什么吗?您希望哪个控制器成为什么的代表,以及您尝试执行哪些 segue?
  • @IlyaLapan 当我点击一个单元格时,我的目标是从一个控制器到另一个控制器,同时将数据从第一个控制器传递到第二个控制器。去控制器是没有问题的,它是通过委托部分传递数据。根据this 之类的问题,您必须在 prepareForSegue 函数中创建要访问的视图控制器的实例,并告诉它发送数据的控制器是它的委托。另一个例子youtube.com/watch?v=KhqXUi1SF4s
  • 你可以从你的单元格中拖出一个 IBOutlet 到你的视图控制器中,然后执行 segue。在为 segue 做准备时,将您的目标视图控制器转换为 B 并传递数据。您还需要将函数声明添加到您的问题中,否则很难理解什么在调用什么以及应该在哪里调用。注释您的代码以显示 sn-p 也属于哪个类。

标签: ios swift delegates protocols


【解决方案1】:

Protocol Delegates 通常用于将数据传递给导航堆栈中的前一个 UIViewController,而不是当前的 UIViewController(在 popViewController 的情况下),因为要发送数据的 UIViewController 需要存在于内存中。在您的情况下,您尚未在内存中初始化 UIViewController B 以执行协议委托的方法。

有一些简单的方法可以将数据发送到导航堆栈中的下一个 UIViewController。

你的 UIViewController B 应该有一个接收变量来存储从 UIViewController A 发送的数据

class DestinationVC : UIViewController
{
    receivingVariable = AnyObject? // can be of any data type depending on the data
}

方法一:使用 Storyboard ID

let destinationVC = self.storyboard.instantiateViewControllerWithIdentifier("DestinationVC") as DestinationVC 
destinationVC.receivingVariable = dataInFirstViewControllerToBePassed
self.navigationController.pushViewController(destinationVC , animated: true)

方法二:使用prepareForSegue

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!)
{
    let destinationVC = segue.destinationViewController as DestinationVC 
    destinationVC.receivingVariable = dataInFirstViewControllerToBePassed
}

从 UIViewController A 到任何其他 UIViewController 的多个 segue 将导致每次执行 prepareForSegue 并可能导致应用程序崩溃,因为其他类 UIViewControllers 将没有 UIViewController 中存在的 receivingVariable 等参数B. 这很容易被反驳;使用多个 segue 可以简单地使用 if else 或在 segue.identifier 上切换模块,这是 segue 的参数。

注意:UILabel、UIButton等其他UI元素的属性不能以这种方式赋值,因为这些元素在UIViewController生命周期的func loadView()中加载到内存中因为当您如上所述初始化 UIViewController B 的类时,它们没有设置为初始化。

【讨论】:

    【解决方案2】:

    我认为您不需要在这里使用委托模式。如果您正在努力实现这一目标。您在视图控制器 A 上有一些单元格,现在您想在视图控制器 B 中显示单元格的详细信息(单击时)。您可以将单元格键声明为视图控制器 B 中的属性。

    class B: UIViewController {
        let cellKey: String!
    }
    

    并在prepare for segue方法中设置上面的key

    if (segue.identifier == "segueToViewControllerB") {
        let vc = segue.destinationViewController as B
        vc.cellKey= "1"
    }
    

    【讨论】:

    • 我已经实现了这个并选择避免它,因为我阅读了here。但是如果没有其他方法,我会使用它。
    【解决方案3】:

    我认为您误解了您所引用问题的要点。上面的问题详细解释了正在发生的事情,但对于那些懒惰的人来说,这里有一个简短的答案:你不准备将信息从下到上传递(即从子视图控制器到父视图控制器),但最肯定的是请务必使用它从上到下传递。

    【讨论】:

    • 哦,好吧,这是有道理的。我想我确实误会了。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多