Search code examples
javaobjective-cswiftinterfaceprotocols

How to implement an Objective-C in Swift without defining a new class


In Java we can declare an interface and then create a new object which conforms to that interface very simply.

public interface Executer {

    void execute();
}

Executer executer = new Executer() {

    @Override
    public void execute() {

        System.out.println("we did it!");
    }
}

Now I want to do the same thing, by defining a protocol in Objective-C and implementing it in Swift.

@protocol Executer <NSObject>
- (void)execute;
@end

How do I implement this protocol in my Swift code like in the Java example?


Solution

  • Swift does not have a direct equivalent of Java's anonymous classes.

    You don't say why you want to do this, e.g. what is it about this construct that makes you want it over what Swift does provide? Given that we'll just show two alternatives, maybe one will suit you.

    Swift supports nested types, so you can declare a local type within your class and instantiate it. For example:

    @objc public class Explore : NSObject
    {
        @objc private class notAnAnonButPrivateClass : NSObject, Executer
        {
            func execute() -> Void
            {
                print("we did it!")
            }
        }
    
        var executer : Executer = notAnAnonButPrivateClass()
    

    This declares the private class and then an instance variable initialised to an instantiation of it.

    If you want to be able to provide the implementation of execute() inline with the declaration then you can do that using a Swift closure (equivalent to block in Objective-C) and use the trailing closure syntax to pretty it up a bit:

    @objc private class notAnAnonButPrivateClass : NSObject, Executer
    {
        let executeImpl : () -> Void
    
        init(_ theImpl : @escaping () -> Void)
        {
            executeImpl = theImpl
        }
    
        func execute() -> Void
        {
            executeImpl()
        }
    }
    
    var executer : Executer = notAnAnonButPrivateClass() {
        print("we did it again!")
    }
    

    In this version the private class' init takes a closure to use for the body of execute() and that closure is written directly in line in the instance variable initialisation.

    This version also differs semantically from the first as the closure may capture values and variables from its enclosing scope.

    So to summarise: you don't get anon classes, you must give them a name (but can use something more sensible than notAnAnonButPrivateClass!) and that name does not "leak" into the rest of your code (the private bit); and you can if you (really) wish provide the method body at the point of instantiation. Maybe one of these will suit you.

    HTH