4

Newish to Swift. Struggling with how to get the most concise/idiomatic syntax for calling an optional delegate method if (a) the delegate is set and (b) the method is implemented.

I know the ? can play this role (eg self.delegate.foo?()) but I'm stymied getting syntax right when trying to call an ObjC delegate method that has multiple arguments and also returns a value (Bool) that I care about capturing (and I want to distinguish between "method not implemented" and "method implemented and returned false").

Here's an example. In this case, MyDelegateProtocol has an optional method -myThing:argTwo:argThree: (returns Bool).

This snippet seems to get the semantics right, but it uses respondsToSelector and is very chatty. Can it be improved in a more idiomatic way?

if let delegate = self.delegate {
    if delegate.respondsToSelector(#selector(MyDelegateProtocol.myThing(_:argTwo:argThree:))) {
        if delegate.myThing!(self, argTwo: foo, argThree: bar) {
            // do something
        }
    }
}
Ben Zotto
  • 70,108
  • 23
  • 141
  • 204

1 Answers1

5

This code should work fine with optionals. And that is all you need to write.

delegate?.myThing?(self, argTwo: foo, argThree: bar)

This code should handle all cases that you were trying to check, e.g.:

if let result = delegate?.myThing?(self, argTwo: foo, argThree: bar) {
     // "result" is the Bool returned from the method
}

If it enters than it means that your method exists and delegate is set. The only problem that may appear is if your method returns an optional Bool? (or any optional) type. Than you can't be sure that your logic is correct and you need to use some sort of checking that you performed in your question. Still in most cases it's unnecessary to know if such method exists, you just calling it if it exists and not calling if not, and my code will handle it.

Ben Zotto
  • 70,108
  • 23
  • 141
  • 204
Volodymyr
  • 1,165
  • 5
  • 16
  • Thank you-- how do I distinguish between "doesn't exist" and "was called and returned false"? – Ben Zotto Aug 27 '16 at 19:25
  • Just use if let unwrapping. It should solve your problem. – Volodymyr Aug 27 '16 at 19:28
  • Or you could just use the `==` overload for optionals – `== true` means the delegate is set, the method was called, and returned `true`, `== false` means the delegate is set, the method was called, and returned `false`, `== nil` means the method isn't implemented or the delegate isn't set. You could easily use a `switch` statement to separate out each case. – Hamish Aug 27 '16 at 19:30
  • Thanks. Just to be absolutely clear, using `if let result = delegate?.myThing?(...) { // "result" is valid }` will not enter the if block scope when no delegate is set or the method doesn't exist, and if it *does* enter the scope, then `result` will be set to the return value of having called it. Right? – Ben Zotto Aug 27 '16 at 19:31
  • Yes, if it enters than it means that your method exists and delegate is set. The only problem that may appear if your method may return optional Bool? type. Than you can't be sure that your logic is correct and you need to use some sort of checking that you performed in your question. Still in most cases it's unnecessary to know if such method exists, you just calling it if it exists and not calling if not, and my code will handle it. If you need additional logic when it exists or not it may produce some problems that I described previously in this comment. – Volodymyr Aug 27 '16 at 19:35
  • 1
    And want to admit it's the same not only for Bool but for any type. If you method return Optional type, than this check does not ensure you about method existence or that delegate is not nil(not set). – Volodymyr Aug 27 '16 at 19:40
  • Thank you. I'm moving your further comments here into the answer. – Ben Zotto Aug 27 '16 at 19:42