0

In Java there is a pattern where a delegate can be declared in-line, instead of making the parent class conform to the interface:

For example:

public class MyClass {

    interface Delegate {
        void completion(Boolean succeeded);
    }

    void doSomething(Delegate delegate) {
        delegate.completion(true);
    }

    void myMethod() {

        doSomething(new Delegate() { // <-- declared in-line
            @Override
            public void completion(Boolean succeeded) {
                // ...
            }
        });
    }
}

In Swift I can make MyClass conform to the Delegate protocol and override the delegate methods on the class level. How can I do that in-line like in the Java pattern?

Manuel
  • 14,274
  • 6
  • 57
  • 130
  • You can't in Swift but you can declare a function to take a closure. – Joakim Danielson Jan 19 '20 at 13:51
  • Right, that's what I was thinking, if I can declare a closure, why not a whole protocol, which is just a more complex closure. – Manuel Jan 19 '20 at 13:54
  • This might also help: https://stackoverflow.com/questions/24173210/implement-delegate-with-closure-in-swift – Cristik Jan 21 '20 at 06:14
  • Or something even more funkier: https://stackoverflow.com/questions/15438410/creating-delegates-on-the-spot-with-blocks :) – Cristik Jan 21 '20 at 06:16
  • @Cristik Thanks for the link, I will just accept that Swift does not support anonymous classes, and thats it. All these workarounds usually create problems regarding compatibility, portability, stability and extendability down the road. – Manuel Jan 21 '20 at 12:46
  • 1
    Couldn't agree more, I can also tell from experience that the more you try to abstract over what the platform gives you, the more problems you'll run into sooner or later. – Cristik Jan 21 '20 at 14:56

2 Answers2

1

In Swift you cannot define a protocol in-line (inside another Type such as Class, Struct or Enum).

However there is a more modern solution that should be very close to what you are looking for: Closures.

Closures

class MyClass {

    // define your closure, make it as complex as you want
    typealias CompletionType = (Bool) -> ()

    // this method accepts a closure as parameter and will call it
    func doSomething(completion: @escaping CompletionType) {
        completion(true)
    }

}

Test

let myClass = MyClass()

myClass.doSomething { result in
    print(result)
}

Output

true
Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
1

Swift doesn't have the concept of anonymous classes. It has however the concept of nested classes. You could write something like this:

func myMethod() {
    class DelegateImpl: Delegate { ... }

    doSomething(DelegateImpl())
}

Beware, though, that delegates are usually declared as weak, which means that the newly allocated instance would be deallocated right away. This is not related to the way the class is declared (i.e. nested instead of inline), but to the memory management rules of Swift (aka ARC).

However, as others have pointed out, closures might be more suited for this kind of functionality.

Cristik
  • 30,989
  • 25
  • 91
  • 127
  • 1
    Thanks for introducing the correct term `anonymous class`. – Manuel Jan 19 '20 at 15:18
  • That is an interesting workaround, I however get a scope issue: `Class declaration cannot close over value 'completion' defined in outer scope` when I try to call `completion` inside `DelegateImpl`. It seems obvious that `DelegateImpl` cannot access variables declared inside `myMethod`, as it is a class declaration with a different scope than `myMethod`. – Manuel Jan 19 '20 at 15:22
  • 1
    @Manuel - yeah, nested classes can't capture the outer scope, only closures can do this. But there might a workaround for this if you want to stick with protocols, however closures will be involved, you cannot avoid them if you want to capture stuff from the surrounding scope(s). – Cristik Jan 19 '20 at 15:26