Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using an implementation of a Swift protocol within Obj-C

I'm trying to implement a mediator sort of pattern with a mixture of Swift and Obj-C. The issue I'm facing is with how to deal with using the Swift protocol implementation classes from Obj-C. Check out the code to see what I mean:

The Swift protocol and implementation of it:

@objc public protocol TheProtocol {
    func someMethod()
}

@objc public class SwiftClass: NSObject, TheProtocol {
    public func someMethod() {
        print("someMethod Swift")
    }
}

The ObjC-implementation of the protocol:

#import "SwiftAndObjC-Swift.h"
@interface ObjCClass : NSObject <TheProtocol>
- (void) someMethod;
@end


@implementation ObjCClass
- (void) someMethod
{
    NSLog(@"someMethod ObjC");
}
@end

My question is how is it possible to define some type in ObjC which is capable of referencing either a SwiftClass or an ObjCClass. For example this does not compile:

#import "SwiftAndObjC-Swift.h"
...
TheProtocol *p = [[ObjCClass alloc] init];
// Error: "Use of undeclared identifier TheProtocol"

This will compile:

@class TheProtocol
TheProtocol *p = [[ObjCClass alloc] init];

But not p can't be used:

@class TheProtocol
TheProtocol *p = [[ObjCClass alloc] init];
[p someMethod];
// Error: Receiver type "The Protocol" is a forward declaration"

(Adding casts to the assignment and/or method invocation doesn't help)

Any solutions?

like image 948
Gruntcakes Avatar asked Apr 14 '16 17:04

Gruntcakes


1 Answers

In Objective-C, a protocol is not a type. You should declare your protocol-conforming class like so:

id<TheProtocol> p = [[ObjCClass alloc] init];

The reason why your forward declaration compiled is because that's what forward declarations do - they announce to the compiler that a class exists and that the linker will fill it in later in the build process.

(That's why changing to id p =... works too.)

In Swift, we declare classes with something like:

class MyClass : Superclass, Protocol, AnotherProtocol { ... }

In Objective-C we use this:

@class MyClass : SuperClass <Protocol, AnotherProtocol>
// ... 
@end

See the difference? In Swift, protocols and the superclass are mixed into the inheritance declaration, whereas Objective-C treats them very differently.

Protocols and Classes are treated slightly different across the two languages, thus used differently.

id in ObjectiveC is analogous to AnyObject? in Swift. An object which conforms to SomeProtocol is obviously AnyObject or id in Objective-C.

like image 70
Moshe Avatar answered Sep 22 '22 12:09

Moshe