0

I'm new to Swift and I'm trying to rewrite a callback as delegation with typealias and I am lost :(

Here is my code:

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

The errors are:

  • Cannot convert value of type 'String' to expected argument type '(String, String) -> Void'
  • Extra argument in call

The original optional callback definition and call is commented out. I first tried rewriting makeNewNote as a typealias without the protocol but still got the same errors.

I also tried removing ? from MakeNewNote but that yielded a new error:

  • Type '(String, String) -> Void' has no member 'init'

I tried a lot of googling and it's been hours. Can anyone help me figure out what's wrong or point me in the right direction? Thanks in advance.

  • You don't seem to have read any guides on how to write a delegate. You need to write a method, not a type alias in the protocol. See the answer by MakeAppPie. – Sweeper Mar 04 '21 at 02:32

1 Answers1

1

You are confused. There's no value in defining a typealias in a protocol. You might as well make the typealias global. It just defines a type. You want your protocol to define the methods and properties that conforming objects support:

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

That just means that any object that conforms to the NewNoteDelegate protocol must implement the makeNewNote(:,:) function.

I'm not sure what having a function return Void? even does, so I stripped that away.

Also note that having a function with two anonymous parameters is considered bad form in Swift. You should really name all the parameters (except possibly the first one). In Swift, the names let you know the purpose of each parameter.

Consider this sample code (Compiled as a Mac command line tool, but it could just as easily be a Playground. I just happen to dislike playgrounds.)

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

That code outputs

string 1 = 'string 1', string 2 = 'string 2'
Duncan C
  • 128,072
  • 22
  • 173
  • 272