Swift delegate & optional - ios

I've declared this protocol
protocol ReactorDelegate {
func ReactorUpdateUI()
}
In my Model I have a delegate optional property and checking if isn't nill, unwrap it to call the protocol methode provided by the VC.
var delegate:ReactorDelegate?
if delegate {delegate?.ReactorUpdateUI()}
My VC follows the protocol and has the ReactorUpdateUI methode
class VC_Reactor: UIViewController, ReactorDelegate
I'm trying to create an instance of the Model in the VC but this fails
let reactorCore=Reactor()
ERROR: 'Reactor' is not constructible with '()' what let's me know that not all properties have an initial value.
I can work-around it by making my delegate in the VC an implicitly unwrapped optional
var reactorCore:Reactor!
and in the ViewDidLoad with a custom init: reactorCore=Reactor(delegate:self)
I don't understand why I need a custom init(delegate:ReactorDelegate) if I declare the delegate property optional.

You need to mark the method as optional in your delegate protocol:
#objc protocol ReactorDelegate {
optional func ReactorUpdateUI()
}
Then mark your class as #objc and use optional chaining on the method, too:
delegate?.ReactorUpdateUI?()
Note: When writing a protocol, it's easiest to keep everything required and stub out the methods in your class, then when everything works go back and make what you want optional be optional. The error messages you get are pretty opaque, so this way you're working with fewer issues at a time.

You have to declare your protocol like this:
protocol ReactorDelegate: class {
func ReactorUpdateUI()
}
And after, your delegate:
weak var delegate: ReactorDelegate
delegate?.ReactorUpdateUI()

Related

How to handle not used functions from delegates in view controllers

I have a very general view that is created and used by multiple view controllers with 2 buttons, one of them sometimes is hidden depending on the needs.
This view delegates the tap of the two buttons.
protocol TheViewsDelegate: class {
func button1Tapped()
func button2Tapped()
}
Let's put that ViewControllerA creates this view and needs both buttons, this view controller will have to implement both delegate functions and do something inside it.
Now let's say that ViewControllerB creates the same view but just needs one of the buttons. This view controller will have to still implement button2Tapped() even though it will never be called and used.
Is there a way to handle this nicely? I imagine there's a nice solution where I don't need to implement this button2Tapped() if I don't need it.
I thought about making it optional by giving a default implementation but I don't like this solution, I like (and I think it's a good practice) the compiler giving me an error when a method it's not implement. Someone can jump into the project and not realising that he/she hasn't implement button2Tapped when needs to be implemented.
Note: This is a very simple example just to illustrate my question, but the question is more broad as in what to do when a function in a delegate is defined by controller that don't need to implement it.
I believe you want to use:
optional func
There are a couple of ways of declaring a protocol method as optional, one is using optional func which requires using #objc syntax, which a lot of programmers apparently don't like, and the other requires declaring an empty body in the extension of a protocol (which makes it optional by default).
protocol TheViewsDelegate: AnyObject {
func button1Tapped()
}
extension TheViewsDelegate {
func button2Tapped() {}
}
class SomeViewController: UIViewController, TheViewsDelegate {
func button1Tapped() {
// implement
}
}
By giving the protocol an empty body inside an extension of the protocol, that method is optional and does not need to be implemented by conforming objects.
For comparison, the alternative:
#objc protocol TheViewsDelegate: AnyObject {
func button1Tapped()
#objc optional func button2Tapped()
}
class SomeViewController: UIViewController, TheViewsDelegate {
func button1Tapped() {
// implement
}
}

How do you set the delegate for an SFSpeechRecognitionTask?

In most cases, setting a delegate is as simple as implementing the delegate protocol in a class and declaring an instance of that class as the delegate for an instance of whatever you're using.
I actually used this same basic concept for the SFSpeechRecognizer which belongs to the same speech framework in my code. (Pseudocode example):
class myViewControllerClass: SFSpeechRecognizerDelegate{
let mySpeechRecognizer = SFSpeechRecognizer(...)
viewDidLoad(){
mySpeechRecognizer.delegate = self
}
...
//SFSpeechRecognizerDelegate Functions here
...
}
//This works as expected, woo!
However, it seems that SFSpeechRecognitionTask has no delegate property which can be set. I tried implementing the 'SFSpeechRecognitionTaskDelegate' protocol in my class in hopes that it would just magically work. However the delegate functions don't seem to ever be called. Which kind of makes sense, because it has no way of knowing that my view controller should be the delegate so why would it!?
The apple documentation covers the protocol itself and how to use it:
https://developer.apple.com/reference/speech/sfspeechrecognitiontaskdelegate
But the documentation for the task itself doesn't identify any delegate property:
https://developer.apple.com/reference/speech/sfspeechrecognitiontask
Also for reference here's the SFSpeechRecognizer documentation which has the protocol AND identifies a delegate property as you'd expect:
https://developer.apple.com/reference/speech/sfspeechrecognizer
Is there some alternative way I'm supposed to be setting the delegate for an SFSpeechRecognitionTask? Or is it handled in some completely different way?
In SFSpeechRecognizer there is a method
func recognitionTask(with request: SFSpeechRecognitionRequest,
delegate: SFSpeechRecognitionTaskDelegate) -> SFSpeechRecognizerTask
Where you can pass on the delegate for the SFSpeechRecognizerTask.
I did it like this in ViewController:
recognitionTask = speechRecognizer?.recognitionTask(with: speechRecognitionRequest, delegate: self)

Inconsistency in Swift optional protocol behaviour

Coming from .Net, I am trying to learn Swift3/iOS and got puzzled by the following apparent inconsistent behaviour of optional protocol members. I suspect its something got to do with the juggling between objc/swift words, but what am I missing here actually?
// In playground, given below:
#objc protocol SomePtotocol {
#objc optional func someMethod()
}
class SomeDelegate: NSObject, SomePtotocol {
}
class SomeController: NSObject {
var delegate: SomePtotocol = SomeDelegate()
}
// This works and compiles without error
let controller = SomeController()
controller.delegate.someMethod?() // No error, typed as '(() -> ())?'
// But this fails to even compile ??
let delegate = SomeDelegate()
delegate.someMethod?() // Error: 'SomeDelegate' has no member 'someMethod'
I would expect either both to fail or both pass, so if someone could please enlighten me on this anomaly.
The difference between the two blocks of code is the type of the variable involved.
In the first block, delegate is explicitly typed as SomePtotocol, and this protocol defines the someMethod method, so your statement is valid.
In the second block, delegate is implicitly typed as SomeDelegate and although this class conforms to SomePtotocol, it doesn't implement the optional method someMethod, so you get an error.
If you change your second block to
let delegate: SomePtotocol = SomeDelegate()
delegate.someMethod?()
which is equivalent to the first block, then there is no error.

Delegate not working

I have a protocol declared in a class
public protocol demoDelegate {
func willShowdemoResult(DemoGraph: UIView)
}
Now I am calling this in the same class where the protocol is declared.
public class Demo:UIViewController {
public var delegate : demoDelegate!
//some code
self.delegate.willShowdemoResult(self.demoGraph())
}
where demo graph returns a UI graph
func demoGraph() -> UIView {
//some code
return demoGraphView
}
I am getting an error that unexpectedly found nil while wrapping an optional value. I know the reason that I have not initialised the delegate. Can somebody guide me How to initialise the delegate here.
The function is being called in other class
class DemoResult: UIViewController, demoDelegate{
func willShowdemoResult(DemoGraph: UIView)
// some code
}
Please Help
You are getting the error, because Demo.delegate is nil when calling:
delegate.willShowdemoResult(self.demoGraph())
Before you make this call, make sure, that you have set the delegate property. I would recommend this right after initializing Demo or right after DemoResult got the address of the Demo-instance.
Let's assume, you have stored an instance of Demo in DemoResult.demoVC. Then you can set the delegate in DemoResult like this:
demoVC.delegate = self
BTW: It's better to use optional types to store delegates:
public var delegate: demoDelegate?
When delegate is optional, delegate?.willShowdemoResult(self.demoGraph()) won't crash, if delegate has not been initialized yet.

Check if optional protocol method is implemented in Swift?

I have a swift protocol:
#objc protocol SomeDelegate {
optional func myFunction()
}
I one of my classes I did:
weak var delegate: SomeDelegate?
Now I want to check if the delegate has myFunction implemented.
In objective-c I can do:
if ([delegate respondsToSelector:#selector(myFunction)]) {
...
}
But this is not available in Swift.
Edit: This is different from: What is the swift equivalent of respondsToSelector? I focus on class protocols not on classes.
How do I check if my delegate has an optional method implemented?
Per The Swift Programming Language:
You check for an implementation of an optional requirement by writing
a question mark after the name of the requirement when it is called,
such as someOptionalMethod?(someArgument). Optional property
requirements, and optional method requirements that return a value,
will always return an optional value of the appropriate type when they
are accessed or called, to reflect the fact that the optional
requirement may not have been implemented.
So the intention is not that you check whether the method is implemented, it's that you attempt to call it regardless and get an optional back.
You can do
if delegate?.myFunction != nil {
}
I've found it successful to add an extension to the protocol that defines basic default implementation and then any class implementing the protocol need only override the functions of interest.
public protocol PresenterDelegate : class {
func presenterDidRefreshCompleteLayout(presenter: Presenter)
func presenterShouldDoSomething(presenter: Presenter) -> Bool
}
then extend
extension PresenterDelegate {
public func presenterDidRefreshCompleteLayout(presenter: Presenter) {}
public func presenterShouldDoSomething(presenter: Presenter) -> Bool {
return true
}
}
Now any class needing to conform to the PresenterDelegate protocol has all functions already implemented, so it's now optional to override it's functionality.
I normally implement it like this:
self.delegate?.myFunction?()
if the delegate methods returns a value:
var result = defaultValue
if let delegateResult = self.delegate?.myFunction?() else {
result = delegateResult
}
//do something with result
Declaration
#objc public protocol nameOfDelegate: class {
#objc optional func delegateMethod(_ varA: int, didSelect item: Item)
}
Implimetation
if let delegate = nameOfDelegate {
delegate.delegateMethod?(1, didDeselect: node)
}
I know this question is 5 years old, but I would like to share what I found. My solution works as of 2021, XCode 11+, Swift 5.
Say I wanted to figure out whether the function sign follows the GIDSignInDelegate protocol and also know what all the optional functions for GIDSignInDelegate are.
I have to look at the source code of the GIDSignIn module, and this is how.
Click on jump to definition on the main module that is imported. It will lead to a file like this:
Copy the entire line, import GoogleSignIn.GIDSignIn and paste it in the ViewController or whatever .swift file (doesn't really matter).
Within the swift file, right click on the GIDSignIn part of the import line GoogleSignIn.GIDSignIn and jump to definition. This will lead you to the actual module with all the available functions (the functions not marked optional may be stubs, which are required functions in the delegate protocol):
From this file, I can see that there is a sign function that is a stub of GIDSignInDelegate and an optional sign function that is implemented as a method overload.
I used this for GIDSignInDelegate, but you can use the same method to figure out whether any function follows any delegate protocol.

Resources