Conforming to a Obj-C protocol in Swift [duplicate] - objective-c

Ok here is the big problem. I had a library written in ObjC(this). There we had a defined protocol. When I tried to use it in swift file I get constantly:
Type "XXX" does not conform to protocol "XXX"
To simplify things I made up a test project - it should be created as Swift project.
Then create ObjC header file(I called it StupidProtocol.h) with following protocol inside(please note each name and value to exactly match the given including uppercase/lowercase):
#protocol MyProtocol <NSObject>
- (NSString *)getAxisLabel:(id)axis Value:(CGFloat)value;
#end
In bridging header:
#import "StupidProtocol.h"
And then back in Swift file:
class ViewController: UIViewController, MyProtocol
{
func getAxisLabel(axis: AnyObject!, value: CGFloat) -> String! {
return ""
}
}
And baam we got this error again even though auto-complete finishes the getAxisLabel function for me.
I strongly suspect that the problem is with argument "value" and it's function parameter "Value".
Any help will be highly appreciated.
EDIT
Please note that this library is not technically mine, so I cannot change it. I need a way to use it in Swift without changing it's original declaration. My example is only to simplify my problem.
WHAT I TRIED
I have tried following scenarios with no success:
'has different arguments name from those required by protocol' error
func getAxisLabel(axis: AnyObject!, Value value: CGFloat) -> String! {
return ""
}
'has different arguments name from those required by protocol' error
func getAxisLabel(axis: AnyObject!, Value: CGFloat) -> String! {
return ""
}
'type does not conform to protocol'
func getAxisLabel(axis: AnyObject!, Value: CGFloat) -> NSString! {
return ""
}
SOLUTION
See accepted answer

I don't know if this is a bug or not. The Objective-C protocol method
- (NSString *)getAxisLabel:(id)axis Value:(CGFloat)value;
(with uppercase "V" in Value:) is mapped to Swift as
func getAxisLabel(axis: AnyObject!, value: CGFloat) -> String!
(with lowercase "v" in value:), but none of
func getAxisLabel(axis: AnyObject!, value: CGFloat) -> String! { }
func getAxisLabel(axis: AnyObject!, Value: CGFloat) -> String! { }
is accepted by the compiler to satisfy the protocol requirement.
As a workaround, you can annotate the method with an explicit
Objective-C selector name:
class ViewController: UIViewController, MyProtocol
{
#objc(getAxisLabel:Value:)
func getAxisLabel(axis: AnyObject!, value: CGFloat) -> String! {
return ""
}
}

Related

How to use UnsafeMutableRawPointer in Kotlin/Native?

I am trying to implement an observer to the changes of UserDefaults for a given key in iOS part of Multi-platform library written with Kotlin/Native. The Swift signature of the function that I need to implement is:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
But it seem that there is no mapping on Kotlin/Native side for UnsafeMutableRawPointer.
How can I achieve that? The code swift code that I would like to port to Kotlin is the following:
let globalDataStore = UserDefaults(suiteName: "global")
func setObserver() {
globalDataStore?.addObserver(self, forKeyPath: "StringKey", options: NSKeyValueObservingOptions.new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("observeValue: \(change?[NSKeyValueChangeKey.newKey] ?? "NO VLAUE")");
}
As I found in the documentation, the Objective-C version of the observeValue method utilizes void * typed argument as a context. This type is being mapped to Kotlin/Native as a COpaquePointer(see this doc's Pointer types subsection). There is no UnsafeMutableRawPointer representation as K/N currently provides interoperability with the Objective-C only.

Implementing an Objective-C protocol in Swift

I have a protocol that's defined in Objective-C, like:
#protocol MyProtocol <NSObject>
- (void)doStuffWithDictionary:(NSDictionary*)dict
andString:(NSString*)str1
andOptionalString:(NSString*)str2
andOptionalArray:(NSArray*)arr
callback:(void (^)(id result))onSuccess;
#end
...and I'm trying to define a class in Swift that implements this protocol, like:
class MyImpl : Operation, MyProtocol {
func doStuff(withDictionary dict: [AnyHashable : Any]!,
andString str1: String!,
andOptionalString str2: String? = nil,
andOptionalArray arr: NSArray? = nil,
callback onSuccess: ((Any?) -> Void)! {
...
}
}
However I'm getting build errors along the lines of:
Type 'MyImpl' does not conform to protocol 'MyProtocol'
note: candidate has non-matching type '([AnyHashable : Any]!, String!, String?, NSArray?, ((Any?) -> Void)!'
func doStuff(withDictionary dict: [AnyHashable : Any]!, andString str1: String!, andOptionalString str2: String? = nil, andOptionalArray arr: NSArray? = nil, callback onSuccess: ((Any?) -> Void)!
It appears to be upset about the andOptionalArray arr: NSArray? = nil parameter. What is the correct syntax to use here?
I put your protocol in a project and imported it in <ProjectName>-Bridging-Header.h, and Auto Complete suggested this syntax:
public func doStuff(with dict: [AnyHashable : Any],
andString str1: String,
andOptionalString str2: String,
andOptionalArray arr: [Any],
callback onSuccess: #escaping (Any) -> Void) {
}
If you want the String and [Any] to be imported as optional, you need to mark them as nullable in Objective-C:
#protocol MyProtocol <NSObject>
- (void)doStuffWithDictionary:(NSDictionary*)dict
andString:(NSString*)str1
andOptionalString:(nullable NSString*)str2
andOptionalArray:(nullable NSArray*)arr
callback:(void (^)(id result))onSuccess;
#end
As #MartinR suggested in the comments:
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.
This works too and offers different interfaces for different versions of Swift.

How do you define/declare a swift method for an objc protocol that has a reference return type?

I created an objc protocol:
#protocol CGEventTapHandler
- (CGEventRef)onCGEvent:(CGEventTapProxy)proxy type:(CGEventType)type event:(CGEventRef)event;
#end
Then in my swift class I get the signature:
func onCGEvent(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent!) -> Unmanaged<CGEvent>!
Now it gets confusing. I get a number of errors.
First error is:
...: Protocol requires function 'onCGEvent(_:type:event:)' with type '(CGEventTapProxy, type: CGEventType, event: CGEvent!) -> Unmanaged<CGEvent>!'
...: Candidate is not '#objc', but protocol requires it
So I add '#objc' to the signature then I get:
...: Method cannot be marked #objc because its result type cannot be represented in Objective-C
Edited per request:
class ViewController: NSViewController, CGEventTapHandler {
func onCGEvent(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent!) -> Unmanaged<CGEvent>! {
}
}
Not absolutely certain where your error lies, so here is a tutorial that works.
Start with a fresh, new, Swift project targeted to OS X.
Create an Objective-C Protocol
File name: CGEventTapHandler.h. When prompted to create the Bridging-Header, approve.
#import <CoreGraphics/CoreGraphics.h>
#protocol CGEventTapHandler
- (CGEventRef)onCGEvent:(CGEventTapProxy)proxy type:(CGEventType)type event:(CGEventRef)event;
#end
Register Protocol
File name: ...-Bridging-Header
#import "CGEventTapHandler.h"
Adopt Protocol
In you client class, adopt CGEventTapHandler:
import Cocoa
class ViewController: NSViewController, CGEventTapHandler {
func onCGEvent(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent!) -> Unmanaged<CGEvent>! {
return nil
}
}
Compiled, linked, built and ran. No warnings, no errors.

Unable to set the delegate to class in Swift

This is their example function
[GTMagBarDevice sharedDevice].delegate = self;
I tried rewriting it in swift like this
GTMagBarDevice.sharedDevice().delegate = self;
But I am receiving an error "type view controller does not conform to protocol GTMagBarDeviceDelegate"
Any ideas?
Update
I have implemented all the required functions, this is what it says in the .h file i am bridging
#protocol GTMagBarDeviceDelegate <NSObject>
#required
- (void)magbarDevice:(GTMagBarDevice*)device accessoryConnected:(BOOL)state;
- (void)magbarDevice:(GTMagBarDevice*)device componentFailed:(int)components;
And this is the implantation
func magbarDevice(magbarDevice: GTMagBarDevice, accessoryConnected isAccessoryConnected: Bool) {
}
func magbarDevice(magbarDevice: GTMagBarDevice, componentFailed components: Int) {
}
You need to implement the methods that the protocol you are conforming to requires.
It looks like your function signatures are incorrect. Try these instead:
func magbarDevice(device: GTMagBarDevice!, accessoryConnected state: Bool) {
}
func magbarDevice(device: GTMagBarDevice!, componentFailed components: Int32) {
}

iCarousel in swift version 1.2 error (candidate is not Objc but protocol requires it)

I get the following error in swift 1.2 : 'RootViewController' does not conform to protocol 'iCarouselDataSource'
In the below class, when I tryed to implement the third party library iCarousel:
class RootViewController: UIViewController,iCarouselDataSource,iCarouselDelegate
{...}
The auto-fix tool puts an #objc mark in this method that conform the protocol:
#objc func carousel(carousel: iCarousel!, viewForItemAtIndex index: Int, var reusingView view: UIView?) -> UIView?
{}
But then another error appears : Method cannot be marked #objc because the type of the parameter 3 cannot be represented in Objective-C
I appreciate any help or clue, thanks !
Remove var from reusingView, ex:
func carousel(carousel: iCarousel!, viewForItemAtIndex index: Int, reusingView view: UIView!) -> UIView! {
var newView = view
if newView == nil {
//create new view
}
//update data
return newView
}