Swift 4.2:无法让简单的委托协议工作
Posted
技术标签:
【中文标题】Swift 4.2:无法让简单的委托协议工作【英文标题】:Swift 4.2: Can't get simple delegate protocol working 【发布时间】:2019-01-29 12:41:21 【问题描述】:YouTube Screenrecord of my workflow
FirstViewController
import UIKit
class FirstViewController: UIViewController
@IBOutlet weak var label: UILabel!
override func viewDidLoad()
super.viewDidLoad()
let secondViewController = SecondViewController()
secondViewController.delegate = self
extension FirstViewController: DataEnteredDelegate
func userDidEnterInformation(info: String)
label.text = info
print("label changed")
SecondViewController
import UIKit
protocol DataEnteredDelegate: class
func userDidEnterInformation(info: String)
class SecondViewController: UIViewController
weak var delegate: DataEnteredDelegate? = nil
@IBOutlet weak var textField: UITextField!
@IBAction func sendTextBackButton(_ sender: UIButton)
print("button tapped")
delegate?.userDidEnterInformation(info: textField.text!)
【问题讨论】:
你还没有实现协议方法 先删除as! DataEnteredDelegate
你把第二个视图控制器推到哪里了?
***.com/a/37203430/6630644
Passing Data between View Controllers***.com/questions/31075116/…的可能重复
【参考方案1】:
除了缺少的委托收养
class FirstViewController: UIViewController, DataEnteredDelegate
如果视图控制器是在情节提要中设计的,它无法工作。
线
let secondViewController = SecondViewController()
创建一个全新的SecondViewController
实例,它不是故事板中的实例,并且所有出口都未连接。
您必须使用segue 或者您必须使用instantiate 并呈现第二个视图控制器以获得对目标控制器的真正引用。
注意:
在控制器之间共享数据的 Swift 协议/委托方面非常objective-c-ish。 回调闭包更轻量级并且更快捷。
【讨论】:
【参考方案2】:将您的协议实现到您的第一个视图控制器。好的做法是扩展控制器,然后将协议的委托方法放到这个扩展中
extension FirstViewController: DataEnteredDelegate
func userDidEnterInformation(info: String)
...
接下来,您设置其委托的第二个视图控制器可能不是您稍后要呈现的控制器。要正确设置委托,请设置将要呈现的控制器的委托。如果您正在使用 segue,请覆盖 prepare(for:sender:)
并设置向下转换的 segue 目的地的委托。如果您手动呈现视图控制器或正在推送它,请设置您正在呈现/推送的此控制器的委托。
【讨论】:
非常感谢!我已将代码 sn-p 移至扩展程序并修复了其他错误。我不推送或继续(参见更新后的视频),我只想从第二个手动更新第一个 viewController。 @AmandaGarcia 更仔细地阅读了答案。我描述了为什么你的代码不起作用【参考方案3】:您必须将第一个视图控制器更改为
class FirstViewController: UIViewController, DataEnteredDelegate
...
原因是第一个视图控制器没有实现协议,所以不会发生强制转换
【讨论】:
谢谢!!我错过了,已修复,但仍然无法正常工作(请参阅更新后的帖子)【参考方案4】:FirstView 控制器使用下面的代码
import UIKit
class FirstViewController: UIViewController, DataEnteredDelegate
@IBOutlet weak var label: UILabel!
func userDidEnterInformation(info: String)
label.text = info
override func viewDidLoad()
super.viewDidLoad()
let secondViewController = SecondViewController()
secondViewController.delegate = self
func userDidEnterInformation(info: String)
// do your stuff here
【讨论】:
非常感谢!我看到我最初错过了作为超类的 DataEnteredDelegate。我修复了它,但它似乎不起作用(请参阅更新后的帖子)【参考方案5】:检查并更新。
class FirstViewController: UIViewController, DataEnteredDelegate
@IBOutlet weak var label: UILabel!
func userDidEnterInformation(info: String)
label.text = info
override func viewDidLoad()
super.viewDidLoad()
let secondViewController = SecondViewController()
secondViewController.delegate = self
【讨论】:
非常感谢!我看到我最初错过了作为超类的 DataEnteredDelegate。我修复了它,但它似乎不起作用(请参阅更新后的帖子)【参考方案6】:我相信您正面临这个问题,因为您将委托设置为 nil。
尝试这样设置:
weak var delegate: DataEnteredDelegate? = FirstViewController.self as! DataEnteredDelegate
【讨论】:
【参考方案7】:这里不接受SecondViewController的直接初始化。另外,在这两个步骤之后,secondViewController 将被释放并且不存在。
override func viewDidLoad()
super.viewDidLoad()
let secondViewController = SecondViewController() // Not the right way to initialize!
secondViewController.delegate = self. //secondViewController will be released!
【讨论】:
【参考方案8】:问题是,您正在创建一个新的SecondViewController
,而不是标签栏使用的实际SecondViewController
。您需要访问 UITabBarController
正在使用的第二个视图控制器,而不是分配一个新实例,以便将您的 viewDidLoad
实现更改为:
override func viewDidLoad()
super.viewDidLoad()
let secondViewController = self.tabBarController?.viewControllers?.last as? SecondViewController
secondViewController.delegate = self
【讨论】:
【参考方案9】:您的 UIWndow 的 rootViewController 是 UITabBarController,它在您分享的 YouTube 视频链接上可见,因此您需要使用此代码 sn-p 从该位置获取 SecoundViewController
class FirstViewController: UIViewController
@IBOutlet weak var label: UILabel!
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let rootController = appDelegate.window?.rootViewController as! UITabBarController
if let viewControllers = rootController.viewControllers
if viewControllers.count > 0
if let secondViewController = viewControllers[1] as? SecondViewController
secondViewController.delegate = self
这样您的委托就不会为零。
在您当前的解决方案中,您的 SecondViewController
获取新实例但未从情节提要中加载,并且您在委托中获得了 nil,因此委托方法无法调用。
// you have nil refrence to delegate check it here
if (self.delegate != nil)
self.delegate?.userDidEnterInformation(info: textField.text ?? "")
希望有帮助。
【讨论】:
以上是关于Swift 4.2:无法让简单的委托协议工作的主要内容,如果未能解决你的问题,请参考以下文章
将键盘选择为中文(简体)时不调用 UITextView 委托 shouldChangeTextInRange - Swift 4.2 中的手写