How do I call an Swift method with a closure from Objective-c? - objective-c

I have the following Swift method:
public func login(userLogin: String, userPassword: String, completion:#escaping (_ result: Result<Data, PZError>) -> ())
And I would like to call it from Objective-C but can't figure out the closure portion:
[apiController loginWithUserLogin:userLogin userPassword:password completion:???];
What would my completion code look like in Objective-C?

It is not possible to call such a method directly from Objective-C.
If you Result type is an enum with non-trivial "case" objects or a struct, it won't work, because Objective-C doesn't support value types.
Also Objective-C doesn't support generic types like Result<T>.
One way to fix would be to make a wrapper, i.e. write a second method in Swift that adapts the types:
func login(userLogin: String, userPassword: String,
completion: #escaping (_ resultData: Data?, _ resultError: NSError?) -> Void)
In this method you would call your original login, and in the internal completion callback unwrap your Result into Data and NSError (converting from PZError), and pass 'em the caller's completion block.

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.

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

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) {

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)
}
}

What does force unwrapped mean in an expected argument type?

Here is my line of code in Swift, it calls a method:
networkManager.postUserProfile(self, onSuccess: {(username: String, userID: NSNumber, recommendedLessons: [AnyObject]) -> Void in
... code block
}, onFailure: {(error: NSError) -> Void in
... another code block
})
The networkManager class is from Objective-C and is:
- (void)postUserProfile:(Profile *)profile
onSuccess:(void(^)(NSString *username, NSNumber *userID, NSArray *recommendedLessons))successBlock
onFailure:(void(^)(NSError *error))failureBlock;
And the error message is:
error: cannot convert value of type (String, NSNumber, [AnyObject]) -> Void to expected argument type ((String!, NSNumber!, [AnyObject]!) -> Void)!
When calling a method, I understand that the ! operator will force-unwrap an optional. However in this situation, what is the meaning of the ! in the expected argument type?
There are many excellent existing answers (such as these) explaining what implicitly unwrapped optionals are and why they are used, so I won't go into that.
Object pointer types in Objective-C header files are treated as implicitly unwrapped optionals in Swift because the compiler doesn't know if nil is a valid value.
Your code should compile if you add an exclamation mark after each of the types in the block you are passing to postUserProfile:
networkManager.postUserProfile(self, onSuccess: { (username: String!, userID: NSNumber!, recommendedLessons: [AnyObject]!) -> Void in
... code block
}, onFailure: { (error: NSError!) -> Void in
... another code block
})
However, a better solution is to add nullability annotations to your Objective-C header file. The properties you mark nullable will be regular optionals and the rest will be non-optionals.

How to get Objective-C block input parameter in Swift Closure

I need use a Objective-C SDK in my Swift project, the Objc demo is in below
[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
NSLog(#"reslut = %#",resultDic);
}];
It pass a block to payOrder:orderString:: function, but when I call it in Swift, the auto complete help me generate these code
AlipaySDK.defaultService().payOrder(orderString, fromScheme: self.aliAppScheme, callback: { ([NSObject : AnyObject]!) -> Void in
println("Pay Success")
})
in Swift the closure input parameter has no name, in Objc it named resultDict, but in Swift I don't know how to get it pointer, Please help me, Thanks
In the objective C block, it takes an NSDictionary parameter. With Swift closures, the closure is already typed so you don't have to declare NSDictionary as the type and you really don't even need -> Void. Also the , callback: is extraneous in Swift as well because of trailing closures so your final product should be:
AlipaySDK.defaultService().payOrder(orderString, fromScheme: self.aliAppScheme) { resultDict in
println("Pay Success")
}