Xcode 10.2 Swift Error: Function types cannot be represented in Objective-C unless their parameters and returns can be - objective-c

I updated Xcode to 10.2 today and I got the following errors:
Method cannot be marked #objc because the type of the parameter 2
cannot be represented in Objective-C
Function types cannot be represented in Objective-C unless their parameters and returns can be
I don't understand why
It was perfectly fine in 10.1.
This is an example that I have been using for years without any issues.
How can I make this code to compile without errors?
#objc public func myFunction(inputString: String, handler:#escaping ((success: Bool, outPut: NSArray)) -> Void) {
// do stuff
}

Delete the phrase outPut:. It was always illegal; Swift 5 just tightens up at last.
So:
#objc public func myFunction(inputString: String, handler:#escaping (NSArray) -> Void) {

Related

multiple return types in optional function

#objc protocol OptionalProtocol: class { // below error during this type
#objc optional func run5() -> (String?, Int?)
}
error: Method cannot be marked #objc because its result type cannot be represented in Objective-C
#objc protocol OptionalProtocol: class { // no error
#objc optional func run5() -> (String?)
}
I am creating an optional function with multiple return types but a single return type is working fine but when I return more than one value it gives above error.
how to fix it.
Thank you
Objective-C doesn't know tuplets.
The second example doesn't return a tuple, (String?) is practically the same as String?.
If you need to return multiple objects to Objective-C wrap the objects in an array, a dictionary or a custom class.

Typedef Return-Type in Objective-C does not work in Swift

I want to use a Objective-C class in my Swift project and have imported the files and Xcode created the bridge header file and everything is cool... except:
The Objective-C class defines a callback type for a function
typedef void (^SSScanManagerCallback)(BOOL success, NSError *error, NSArray *scannedURLs);
And uses the type in the function declaration
- (void)scanSync:(SSScanManagerCallback)callback; // Synchronous scan.
The class in question is the following: https://github.com/counsyl/scanstream/blob/master/ScanStream/SSScanManager.h#L16
If I then want to use the class in Swift:
let scanManager = SSScanManager();
scanManager.scanSync({(_ success: Bool, _ error: Error, _ scannedURLs: [Any]) -> Void in
if !success {
// ...
}
});
I get the following error:
Cannot convert value of type '(Bool, Error, [Any]) -> Void' to expected argument type 'SSScanManagerCallback!'
Update: Even if I try to set the argument type like so:
scanManager.scanSync({(_ justATry: SSScanManagerCallback!) -> Void in
});
I get the error:
Cannot convert value of type '(SSScanManagerCallback!) -> Void' to expected argument type 'SSScanManagerCallback!'
But how would I set the type to just 'SSScanManagerCallback!' as requested in the error message?
Interestingly, it appears that Swift (tested with 3.0.2) now imports Objective-C block argument types without any nullability annotations as strong optionals (previously they were imported as implicitly unwrapped optionals). I can't seem to find the documentation for this change though.
So in your case, the correct signature is:
scanManager.scanSync {(success: Bool, error: Error?, scannedURLs: [Any]?) -> Void in
// ...
}
But never write it like this, always let Swift infer the argument types where it can, it solves these kinds of type-mismatch problems for you.
scanManager.scanSync { success, error, scannedURLs in
// ...
}
Now you can ⌥ click on the closure arguments and Xcode will tell you the type that Swift infers them to be.

From Swift 3, how to use a type defined as an Obj-C block taking an id * pointer as parameter

My Swift 3.0 project uses an Objective-C library that defines a certain type (AsyncBlock) as an Obj-C block:
typedef BOOL (^AsyncBlock)(id __nullable * __nonnull context);
In Swift 3.0 terms, that should translate into a non optional pointer to an optional value, so I figured I should be able to assign a variable of type AsyncBlock to a closure defined in my swift 3 project as follows (not including bridging header and other details for brevity):
func closure(_ context: UnsafeMutablePointer<Any?>) -> Bool {
return true
}
var myClosureVariable: AsyncBlock = closure
The compiler disagrees: Cannot assign value of type '(UnsafeMutablePointer<Any?>) -> Bool' to type 'AsyncBlock' - what am I doing wrong?
An Obj-C id normally maps to a Swift 3.0 Any, but here we have to use AnyObject (not sure why). Also we need to use an AutoreleasingUnsafeMutablePointer instead of an UnsafeMutablePointer (again, not clear as to the reasons why)
This works:
func closure(_ context: AutoreleasingUnsafeMutablePointer<AnyObject?>) -> Bool {
return true
}
var myClosureVariable: AsyncBlock = closure

Convert complex Objective-C macros to swift

I've used a library named LinqToObjectiveC in my project and now I want to use it in swift files. this library uses complex objective-C macros which are not accessible in swift. I want to know how can I convert for example this macro to swift:
#define LINQKey(__key) (^id(id item){return [item valueForKey:##__key];})
First let's explain what that macro is doing.
It takes an argument called __key, stringifies it (# and #) and returns a closure (block) that will take an object as an parameter and returns the result of item.valueForKey(key).
We can't convert stringification to Swift, however, that's something that shouldn't be used even in Obj-C. Why should we have LINQKey(myKey) when we can have LINQKey(#"myKey")?
As a simple function that returns a closure:
func LINQKey(key: String) -> (AnyObject! -> AnyObject!) {
return { (item: AnyObject!) in
return item.valueForKey(key)
}
}

Bridging from Objective C to Swift with PromiseKit

Using PromiseKit 2.0 with Swift 1.2, I'm trying to use a PMKPromise that was created in Objective C from Swift.
Objective C code:
#interface FooTest : NSObject
+ (PMKPromise *)promise;
#end
Swift code (I've tried a number of variations, none of which work. This one is closest to the example given at http://promisekit.org/PromiseKit-2.0-Released/):
FooTest.promise().then { (obj: AnyObject?) in
self.obj = obj
}
Compiler error: Cannot invoke 'then' with an argument list of type '((AnyObject?) -> _)'
This doesn't work either:
FooTest.promise().then { (obj: AnyObject?) -> AnyPromise in
return AnyPromise()
}
Similar error: "Cannot invoke 'then' with an argument list of type '((AnyObject?) -> AnyPromise)'"
There are two different promise classes in PromiseKit, one for Swift (Promise<T>) and one for ObjC (AnyPromise). The Swift ones are generic and Objective-C cannot see generic classes, so this is why there are two.
If Foo.promise() is meant to be used in both ObjC and Swift then you are doing the right thing. If however you only intend to use this promise in Swift then I suggest rewriting it as a Promise<T>.
To use an Objective-C AnyPromise (PMKPromise is a deprecated alias for AnyPromise: prefer AnyPromise) in Swift code you must splice it into a an existing chain.
someSwiftPromise().then { _ -> AnyPromise in
return someAnyPromise()
}.then { (obj: AnyObject?) -> Void in
//…
}
There should be a way to start from an AnyPromise, probably I will add this later today:
someAnyPromise().then { (obj: AnyObject?) -> Void in
//…
}
Expect a 2.1 update. [edit: 2.1 pushed with the above then added]