使用 typealias 从回调转移到委托

Posted

技术标签:

【中文标题】使用 typealias 从回调转移到委托【英文标题】:Moving from callback to delegation with typealias 【发布时间】:2021-06-02 16:03:15 【问题描述】:

我是 Swift 新手,我正在尝试用 typealias 将回调重写为委托,但我迷路了 :(

这是我的代码:

protocol NewNoteDelegate: class 
    typealias MakeNewNote = ((String, String) -> Void)?


class NewNoteViewController: UIViewController 
    @IBOutlet weak private var titleField: UITextField?
    @IBOutlet weak private var noteField: UITextView!
    weak var delegate: NewNoteDelegate?
    
//    public var makeNewNote: ((String, String) -> Void)?
    
    override func viewDidLoad() 
        super.viewDidLoad()
        titleField?.becomeFirstResponder()
        
        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Save", style: .done, target: self, action: #selector(didTapSave))
    
    
    @objc func didTapSave() 
        if let text = titleField?.text, !text.isEmpty, !noteField.text.isEmpty 
//            makeNewNote?(text, noteField.text)
            delegate?.MakeNewNote(text, noteField.text)
        
    

错误是:

无法将“String”类型的值转换为预期的参数类型“(String, String) -> Void” 调用中的额外参数

原来的可选回调定义和调用被注释掉了。我首先尝试在没有协议的情况下将makeNewNote 重写为类型别名,但仍然遇到相同的错误。

我还尝试从MakeNewNote 中删除?,但这产生了一个新错误:

类型 '(String, String) -> Void' 没有成员 'init'

我尝试了很多谷歌搜索,已经好几个小时了。谁能帮我找出问题所在或指出正确的方向?提前致谢。

【问题讨论】:

您似乎没有阅读任何有关如何编写委托的指南。您需要在协议中编写方法,而不是类型别名。请参阅 MakeAppPie 的答案。 【参考方案1】:

你很困惑。在协议中定义类型别名没有任何价值。您不妨将 typealias 设为全局。它只是定义了一个类型。您希望您的协议定义符合对象支持的方法和属性:

protocol NewNoteDelegate: class 
    func makeNewNote(_: String, _: String)

这只是意味着任何符合 NewNoteDelegate 协议的对象都必须实现 makeNewNote(:,:) 函数。

我不确定函数 return Void? 的作用,所以我把它去掉了。

另请注意,在 Swift 中,具有两个匿名参数的函数被认为是错误的形式。您应该真正命名所有参数(可能第一个参数除外)。在 Swift 中,名称让您知道每个参数的用途。

考虑一下这个示例代码(编译为 Mac 命令行工具,但它也可以很容易地成为 Playground。我只是碰巧不喜欢 Playground。)

import Foundation

protocol NewNoteDelegate: class 
    func makeNewNote(_: String, _: String)


//The Foo class has a delegate that conforms to the NewNoteDelegate protocol.
class Foo 
    weak var delegate: NewNoteDelegate?

    func doSomething(string1: String, string2: String) 
        //Invoke our delegate, if we have one.
        delegate?.makeNewNote(string1, string2)
    



//This class just knows how to be a NewNoteDelegate
class ADelegate: NewNoteDelegate 
    func makeNewNote(_  string1: String, _ string2: String)
        print("string 1 = '\(string1)', string 2 = '\(string2)'")
        return
    


//Create a Foo object
let aFoo = Foo()

//Create an ADelegate object
let aDelegate = ADelegate()

//Make the ADelegate the Foo object's delegate
aFoo.delegate = aDelegate

//Tell our foo object to do something.
aFoo.doSomething(string1: "string 1", string2: "string 2")

该代码输出

string 1 = 'string 1', string 2 = 'string 2'

【讨论】:

以上是关于使用 typealias 从回调转移到委托的主要内容,如果未能解决你的问题,请参考以下文章

Swift typealias associatedType

尝试从 UIView 的按钮转移到另一个 ViewController 时,委托不起作用

如何在 Swift 中的框架内创建委托/回调? [复制]

从服务器获取数据时如何使用 typealias

注册 C# 委托给 C++ 回调,Marshal.GetFunctionPointerForDelegate 有啥作用?

asihttp 使用 POST 方法并将 nsMutabledata 发布到 uri,为啥我无法获得 asi 委托回调?