Reputation: 7068
I have a protocol defined in Swift:
@objc public protocol UploadProtocol: class {
func isUploaded() -> Bool
...
}
I'm importing my ProjectName-Swift.h
file in my ProjectName_Prefix.pch
file (old project).
In Objective-C I have a category on a class which implements the protocol. I'm trying to figure out how to let the compiler know about that implementation. This is what I have been doing:
// Person+Upload.h
#import "Person.h"
@interface Person (Upload)
- (BOOL)isUploaded;
@end
// Person+Upload.m
#import "Person+Upload.h"
@implementation Person (Upload)
...
@end
This gives me:
Cannot find protocol definition for 'UploadProtocol'
I can only think of three other ways of setting this up and all of them have problems. What am I missing?
In Using Swift with Cocoa and Objective-C (Swift 2.2), Apple says, "An Objective-C class can adopt a Swift protocol in its implementation (.m) file by importing the Xcode-generated header for Swift code and using a class extension." But their example is for a standard class. If I try to do this with my category:
// Person+Upload.h
#import "Person.h"
@interface Person (Upload)
- (BOOL)isUploaded;
@end
// Person+Upload.m
#import "Person+Upload.h"
@interface Person (Upload) <UploadProtocol>
@end
@implementation Person (Upload)
...
@end
This results in:
Duplicate definition of category 'Upload' on interface 'Person'
Ok, so I want to avoid defining the upload class twice. So I'll remove it from the .h
.
// Person+Upload.h
#import "Person.h"
@interface Person ()
- (BOOL)isUploaded;
@end
// Person+Upload.m
#import "Person+Upload.h"
@interface Person (Upload) <UploadProtocol>
@end
@implementation Person (Upload)
...
@end
In this case I get:
Category is implementing a method which will also be implemented by its primary class
I'm currently declaring the method in the .h
so that other classes can call some of those methods without casting to the protocol to access that method.
If I leave the category name in the .h
but take it off in the .m
// Person+Upload.h
#import "Person.h"
@interface Person (Upload)
- (BOOL)isUploaded;
@end
// Person+Upload.m
#import "Person+Upload.h"
@interface Person () <UploadProtocol>
@end
@implementation Person (Upload)
...
@end
Then I get:
Category is implementing a method which will also be implemented by its primary class
Is the only solution to cast it to the protocol every time? Adding this type of line in multiple places seems like a code smell:
Person <Upload> *s = (Person <Upload> *)self;
Any other solutions?
Upvotes: 1
Views: 2009
Reputation: 4891
Thanks for the interesting question!
Your initial approach will actually work with an addition of a forward declaration of the protocol:
// Person+Upload.h
#import "Person.h"
@protocol UploadProtocol; // NOTE THIS!!!
@interface Person (Upload) <UploadProtocol>
//- (BOOL)isUploaded; // This is not really needed
@end
// Person+Upload.m
#import "Person+Upload.h"
#import "...-Swift.h" // IMPORTANT!!!
@implementation Person (Upload)
// HERE you implement isUploaded, of course.
...
@end
This will still cause a compiler warning Cannot find protocol definition for 'UploadProtocol'
, but it should work.
The Apple-recommended way also works, the Duplicate definition of category
is just a warning, but Person
won't be recognized as conforming to the protocol by Swift code, even though its conformance will be recognized by Objective-C. The initial approach will be fine in Swift, too.
Upvotes: 1