Reputation: 1440
I've read along here and here about conforming to Swift protocols in Objective-C headers, and I'm not quite getting the behaviour I want - I'm also looking for a better understanding of how this all works. Here's my scenario.
I have a protocol in Swift:
@objc
protocol PersonalDetailsProtocol {
func doSomeWork()
}
I then have an Objective-C class with a header and implementation file
@protocol PersonalDetailsProtocol; // Forward declare my Swift protocol
@interface RegistrationPersonalDetails : NSObject <PersonalDetailsProtocol>
@end
#import "RegistrationPersonalDetails.h"
@implementation RegistrationPersonalDetails
- (void)doSomeWork {
NSLog(@"Working...");
}
@end
At this point everything compiles, although there is a warning in the RegistrationPersonalDetails.h
file stating Cannot find protocol definition for 'PersonalDetailsProtocol'
. Other than that warning, the issue I'm facing is I can't publicly call the doSomeWork
method on an instance of RegistrationPersonalDetails
.
The call site in Swift would look something like:
let personalDetails = RegistrationPersonalDetails()
personalDetails.doSomeWork()
but I get an error stating:
Value of type 'RegistrationPersonalDetails' has no member 'doSomeWork'
I get that the method isn't public, because it's not declared in the header file. But I didn't think it should have to be as long as the protocol conformance is public i.e. declared in the header file.
Can anyone point me on the right path here and offer an explanation? Or is this even possible? I can obviously rewrite the protocol in ObjC, but I just always try to add new code as Swift.
Upvotes: 1
Views: 1149
Reputation: 2433
In pure objective-c, you cannot make a class conform to a protocol without importing it in the header. To make the use of a protocol private, the conformance shouldn't be declared in the header. It remains possible to call such a method using a cast however, but it should be done with caution because it's a little bit unsafe :
if ([anInstance respondToSelector:@selector(myProtocolMethod)])
[(id<MyProtocol>)anInstance myProtocolMethod];
I'm not familiar with Swift, but I think you can do the same this way (or something close to it) :
if let conformingInstance = anInstance as? MyProtocol
conformingInstance.myProtocolMethod
EDIT : To complete my first assertion, forward declarations can still be used in the header when you need to declare a method receiving or returning an instance conforming to that protocol :
@SomeProtocol;
// This is not possible
@interface MyClass : NSObject <SomeProtocol>
// But this is possible
@property (nonatomic) id<SomeProtocol> someProperty;
-(void) someMethod:(id<SomeProtocol>)object;
@end
In this document Apple clearly said that :
Forward declarations of Swift classes and protocols can be used only as types for method and property declarations.
So it seems that the rule is the same whatever the protocol is an Objective-c protocol or a Swift protocol.
Upvotes: 2