Implement Objective c protocol in Swift - objective-c

I have this protocol in a objective c class:
#protocol YTManagerDelegate <NSObject>
#required
- (void)uploadProgressPercentage:(int)percentage;
#end
...
and a swift class connected to it:
class YTShare: UIViewController, YTManagerDelegate{
func uploadProgressPercentage(percentage:Int?){
println(percentage)
}
...
I receive the error: type YTShare does not conform to protocol YTShareDelegate, I have probably write incorrectly the swift function so the obj class don't find it. How I can write it correctly?

There are two errors in the delegate method
func uploadProgressPercentage(percentage:Int?){
println(percentage)
}
The parameter must not be an optional, and the C type int is mapped to Swift
as CInt (an alias for Int32):
func uploadProgressPercentage(percentage:CInt){
println(percentage)
}
Alternatively, you could use NSInteger in the Objective-C protocol, which is
mapped to Int in Swift. This would be a 32-bit or 64-bit integer, depending
on the architecture, whereas int/CInt is always 32-bit.

Related

iOS11 Swift 4 - how to check if Swift class conforms to protocol defined in Objective-C?

I have a legacy code base with code written in Objective-C. I'm adding a new class written in Swift which has to conform to existing protocols defined in Objective-C.
How can I make sure my Swift class correctly implements methods defined in Objective-C protocol?
//In Obj-C
#protocol OBJCLocationObserver <NSObject>
- (void)didUpdateLocationWithModel:(nullable Model *)locationModel
lastLocation:(CLLocationCoordinate2D)lastLocation;
#end
//In Swift
extension SwiftLocationManager : OBJCLocationObserver
{
public func didUpdateLocation(with model: Model?, lastLocation: CLLocationCoordinate2D) {
// How to verify this function signature is actually conforming to the Obj-C protocol and is not a new method?
}
}
[MyClass conformsToProtocol:#protocol(MyProtocol)];
According to Apple Docs you can use conformsToProtocol:which returns a Boolean value that indicates whether the receiver conforms to a given protocol.
Example
#protocol MyProtocol
- (void)helloWorld;
#end
#interface MyClass : NSObject <MyProtocol>
#end
Will be exposed as:
console.log(MyClass.conformsToProtocol(MyProtocol));
var instance = MyClass.alloc().init();
console.log(instance.conformsToProtocol(MyProtocol))
Make sure you #import your protocol definition file into the <ProjectName>-Bridging-Header.h file:
#import "OBJCLocationObserver.h"
And then you should see error messages if your signature does not match.
You can also use Xcode Auto Completion. Type:
public func didUpdateLocation
and Auto Complete suggests:
public func didUpdateLocation(withModel Model?, lastLocation: CLLocationCoordinate2D)
which is different than what you have and explains why it isn't working.
Here is another way to get the interface:
As #MartinR suggested on a comment to another question:
Go to the header file where the protocol is defined, and choose
"Generated Interface" from the "Related Items" popup in the top-left
corner. That will show you the exact Swift method signature that you
have to implement.

Swift & Objective C protocols: throwing function declaration [duplicate]

I have Objective-C Protocol
#protocol SomeObjCProtocol
- (BOOL) doSomethingWithError: (NSError **)error;
#end
And Swift class
class SwiftClass : SomeObjCProtocol
{
func doSomething() throws {
}
}
Compilers gives me an error
Type 'SwiftClass' does not conform to protocol 'SomeObjCProtocol'"
Is there any solution how to get rid of this error?
I'm using XCode 7 Beta 4
There are two problems:
Swift 2 maps func doSomething() throws to the Objective-C method
- (BOOL) doSomethingAndReturnError: (NSError **)error;, which is
different from your protocol method.
The protocol method must be marked as "Objective-C compatible" with the #objc attribute.
There are two possible solutions:
Solution 1: Rename the Objective-C protocol method to
#protocol SomeObjCProtocol
- (BOOL) doSomethingAndReturnError: (NSError **)error;
#end
Solution 2:
Leave the Objective-C protocol method as it is, and specify the Objective-C mapping for the Swift method
explicitly:
#objc(doSomethingWithError:) func doSomething() throws {
// Do stuff
}
When encountering that error message, one source of the problem might be that the Swift class conforming to the Objetive C protocol was not inherited from NSObject.

String! does not conform to protocol 'ExpressibleByStringLiteral'

I am trying to use a method that was defined as Objective C method, from a swift file
the method in objective c is defined as
-(instancetype) init:(NSString*)string data:(id)data;
the method name cannot be refactored.
I am trying to invoke it as follows
let myObject = MyObject("MyString",data:["1","2","3"])
in return i am getting the compile error : "String! does not conform to protocol 'ExpressibleByStringLiteral'"
How can I fix it?
EDIT:
MyObject is defined as follows
`#interface MyObject<__covariant Type> : NSObject #end
#implementation
#end`
In Swift 3, ObjC generics are imported as Swift generics. And you always need to specify the type parameter in Swift generics. (And Swift 3 is not yet so refined as to generate appropriate diagnostics...)
let myObject = MyObject<NSString>("MyString",data:["1","2","3"])
worked.
Is your data actually data, or a [String]?

How to use NSSet<Class> in Swift (exported as Set<NSObject>)?

I have to fulfill a protocol requirement that is defined in Objective-C like this:
#protocol AProtocol <NSObject>
+ (NSSet<Class> * _Nullable)someClasses;
#end
I want to implement this protocol in a subclass written in Swift. I want to return a Set of classes of another Object. The class I want to return is defined like this:
class B: NSObject {}
The class that conforms to the protocol is defined like this:
class A: NSObject, AProtocol {
static func someClasses() -> Set<NSObject>? {
return [B.self]
}
}
Why is NSSet<Class> bridged to Set<NSObject> instead of Set?
This solution is crashing, how can I solve the problem?
NSSet<Class> is bridged to Set<NSObject> because AnyClass does not conform to Hashable which is a precondition for the ValueType of Set.
It can be solved with the following extension for NSObjectProtocol:
extension NSObjectProtocol where Self: NSObject {
static var objcClass: NSObject {
return (self as AnyObject) as! NSObject
}
}
This returns the class of the object casted as NSObject. It is necessary to cast it first to AnyObject because the type system of Swift is so strong that it would not compile or give a warning when directly casting a type to an instance type. In Objective-C this is fine because Class is also just an object. Since NSObject is implemented in Objective-C and the extension is just for NSObjectProtocol, this is save to use (even with the force cast).
Implementing the extension on NSObjectProtocol and not on NSObject itself brings the positive effect that it is not exported to Objective-C.

Pass #protocol type in Swift

I have an Objective-C method which takes Protocol* type as parameter.
How can I invoke this method in Swift.
Example:
// In Objective-C
#protocol AProtocol <NSObject>
#end
#interface MyClass : NSObject
+ (id)proxyWithProtocol:(Protocol*)protocol;
#end
// I can call this method with a protocol as parameter
[MyClass proxyWithProtocol:#protocol(AProtocol)];
If I want to use MyClass in Swift by bridging. How can I pass a protocol defined in Objective-C to proxyWithProtocol method. Can I even pass a protocol defined in Swift to this method?
You would pass the Objective-C protocol in like so:
MyClass.proxyWithProtocol(AProtocol)
If you wanted to pass in a Swift protocol, you would have to expose that protocol to Objective-C:
#objc protocol MyProtocol {
func someGreatFunc()
}
// ...
MyClass.proxyWithProtocol(MyProtocol)
In Swift 3, depending on the way the class is bridged to Swift, your function might look like this:
MyClass.proxy(with: AProtocol)
MyClass.proxy(with: MyProtocol)
Although the compiler isn't happy with the location of "with" and may complain.