I Convert my Objective C + Swift 2.x code to Swift 3 in Xcode 8. After converting the code i am getting these new warning that i don't know if it's safe ti ignore/how to resolve it.
My Swift 3 code :
func getUserNotificationFromServer(_ completionQueue:DispatchQueue = DispatchQueue.main,callback: #escaping (_ succeeded: Bool, _ response: AnyObject?) -> Void) {
Objective C code that calls this function
[wsManager getUserFavouritesFromServer:dispatch_get_main_queue() callback:^(BOOL succeeded, id _Nullable response) {
Warning that i am receiving
Incompatible pointer types sending 'dispatch_queue_t _Nonnull' (aka
'NSObject *') to parameter of type
'OS_dispatch_queue * _Nonnull'
Any thoughts ?
I don't understand why, but the DispatchQueue is exposed as OS_dispatch_queue * in the generated {ProjectModuleName}-Swift.h .
(Better send a bug report to Apple.)
As far as I tested, just casting as suggested in the message suppresses the warning, and the code works as expected:
[wsManager getUserNotificationFromServer:(OS_dispatch_queue * _Nonnull)dispatch_get_main_queue()
callback:^(BOOL succeeded, id _Nullable response) {
Related
In an iOS app using parse-server (on Heroku/mLab), I am having the following issue with a cloud function.
Here is the relevant code:
PFCloud.callFunction(inBackground: "myCloudFunction",
withParameters: ["lastTouch" : theLastTouchStamp]) {
(any: Any, error: Error) in
print("Now Inside Block (myCloudFunction)")
}
Here is the error message I get from the compiler:
Cannot convert value of type '(Any, Error) -> ()' to expected argument type 'PFIdResultBlock?'
I have browsed the net in search for some information, but eventhough I found a couple of related post; nothing led me to a solution.
Does anybody know how to solve this?
Remove the types from the closure:
PFCloud.callFunction(inBackground: "myCloudFunction", withParameters: ["lastTouch" : theLastTouchStamp]) {
(value, error) in
print("Now Inside Block (myCloudFunction)")
}
I am a bit confused on how to use completion handlers in Swift 3. Previously, in Swift 2.2, I had code like this:
transferUtility.uploadFile(tmpFileURL, bucket: bucket, key: key, contentType: contentType, expression: nil, completionHander: { (task, error) in
self.uploadCompletionHandler(task, transferError: error)
})
How can I port this to Swift 3?
I get an error that says Cannot convert value of type '(AWSS3TransferUtilityUploadTask, NSError) -> ()' to expected argument type 'AWSS3TransferUtilityUploadCompletionHandlerBlock?'
Does anyone know what could be wrong?
Check the signature of the AWSS3TransferUtilityUploadCompletionHandlerBlock, now Swift 3 doesn't allow auto type-casting. Swift 3 doesn't allow you to define the completionBlock with different signature, check the ? and ! as well.
I have working project in Xcode 7.3 with swift 2.2 version. Now I have updated Xcode 8 and migrated to swift 3. Now my project contains errors specially for blocks like success block of afnetworking.
Which gives error as
Cannot convert value of type '() -> ()' to expected argument type '((URLSessionDataTask, Any?) -> Void)?'
I don't understand how to solve this to work as per swift 3.
And there is also same like error in Facebook login.
Which gives error as
Cannot convert value of type '(FBSDKLoginManagerLoginResult!, NSError!) -> Void' to expected argument type 'FBSDKLoginManagerRequestTokenHandler!'
and
Cannot convert value of type '(_, _, NSError!) -> Void' to expected argument type 'FBSDKGraphRequestHandler!'
This all errors are related to handler blocks in swift 3. I don't understand the errors and so that can't able to solve. Any help will be appreciated. Thanks in advance.
For facebook - the problem is in new Swift rules about converting objective-c function parameters into Swift.
Previously, if parameters in objective-c code did not have nullability attributes(like nonnull or nullable), Swift converts it with ! making them non optional(forced unwrapping). Now it convert it with ? making them optional. That why you are getting an error. Before you were putting as a callback for login:
(FBSDKLoginManagerLoginResult!, NSError!) -> Void
Now you need to put:
(FBSDKLoginManagerLoginResult?, Error?) -> Void
Also, as you see, now you will not see NSError class. Instead of that Swift will put Error.This is also new rule. Now all "NS" prefixed in class names is removed in Swift(NSObject -> Object; NSError -> Error).
Example of working code for facebook login in Swift 3.0:
let manager = FBSDKLoginManager()
manager.logIn(withReadPermissions: ["public_profile"], from: self.controller) {
(loginResult: FBSDKLoginManagerLoginResult?, error: Error?) in
}
Example of working code for facebook request in Swift 3.0:
let request = FBSDKGraphRequest()
request.start {
(connection: FBSDKGraphRequestConnection?, result: Any?, error: Error?) in
}
As you see, now it is using Any type instead of objective-c id. In Swift 2.2 it was using AnyObject. It is also new Swift converting rule.
You do not need to specify callback parameters type. I did that in code for highlighting their real types. So you can just write code without them:
let manager = FBSDKLoginManager()
manager.logIn(withReadPermissions: ["public_profile"], from: self.controller) { (loginResult, error) in }
let request = FBSDKGraphRequest()
request.start { (connection, result, error) in }
But you need to remember that they are optional now.
In conclusion some converting rules that may affect you callback code:
Closure parameters are optional if in objective-c are not specified nullability attributes
All "NS" prefixes is removed for objective-c classes in Swift
If objective-c function had id parameter, in Swift 3.0 it will have type Any instead of AnyObject
Though I didn't know the error before that what Xcode want to inform me about the error, but I have removed type specification with object and it worked.
As
manager.post(methodname, parameters: param, progress: nil, success:{ (dataTask, responseObj) in
if let dict : NSDictionary = responseObj as? NSDictionary {
print("Response of \(methodname) : \(dict)")
if dict.object(forKey: "response") as? String == "success" {
CompletionHandler(true, dict)
} else {
CompletionHandler(false, dict)
}
}
})
Here with respect to question error is given at dataTask and responseObj which are with type specified. After removing type it worked fine.
Same as with facebook login
#IBAction func fbLoginClicked(_ sender: AnyObject) {
let app = UIApplication.shared.delegate as! AppDelegate
app.fbLoginManager = FBSDKLoginManager()
app.fbLoginManager.logOut()
app.fbLoginManager.loginBehavior = FBSDKLoginBehavior.native
app.fbLoginManager.logIn(withReadPermissions: ["email"], from: self, handler: { (result, error) -> Void in
if error != nil {
print(error?.localizedDescription)
} else {
if (result! as FBSDKLoginManagerLoginResult).isCancelled == true {
} else {
self.fetchFacebookUserDetail()
}
}
})
}
Here also I have removed type specification of result and error and problem solved. And followed this in whole app and it worked. I can run the project without error and also it is working. Thanks.
I am simply trying to convert this Objective-C block to swift but there seems to be a problem, I am unable to solve. None of the variables are optional.
Objective-C - Works
[CLPlacemark hnk_placemarkFromGooglePlace:place
apiKey:YOUR_API_KEY
completion:^(CLPlacemark *placemark, NSString *addressString, NSError *error) {
}];
Swift - Gives error
CLPlacemark.hnk_placemarkFromGooglePlace(placeAtIndexPath(indexPath),"YOUR_API_KEY",
completion:{ (placemark:CLPlacemark!, addressString: NSString!, error: NSError!) -> Void in
})
Error Message:
Cannot invoke 'hnk_placemarkFromGooglePlace' with an argument list of type '(HNKGooglePlacesAutocompletePlace!, String, completion: (CLPlacemark!, NSString!, NSError!) -> Void)'
Swift Method Signature
CLPlacemark.hnk_placemarkFromGooglePlace(place:
HNKGooglePlacesAutocompletePlace!, apiKey:String!, completion:
((CLPlacemark!, String!, NSError!) -> Void)
Swift bridges NSString to String in blocks. You still use NSString in your callback, but should use String.
If you're using Swift 1.2 (or maybe even 1.1) String and NSString are compatible, but the compiler requires that you cast them. Think something like: NSString(string: mySwiftString) or String(myNSString). The error shows that you're using both a String and NSString, make sure you're using the right one in the right places.
I would like to call a completion block in Swift as I have always done in Objective-C. I took a look at closures, but for some reason, I cannot get it to work...
Obj-C:
- (void)someMethodWithParam1:(NSString *)param completion:(void(^)(NSArray* arr, NSURLResponse *resp))callback
{
callback(arr, resp);
}
Swift:
func someMethodWithParam1(param: NSString, completion:((NSArray?, NSURLResponse?)->())) ->(){
^
|
/* Error: Insert ',' here */
completion(arr, resp)
}
EDIT
Okay, it was not a syntactical error, but an error from my side. The method header I used here is different from the one in my code. So this code that I originally posted should work fine.
Typealias's are your friend here, just to make the code more readable
typealias onComplete = (NSArray?, NSURLResponse?) -> ()
func someMethodWithParam1(param: NSString, completion:onComplete) -> ()
{
completion(arr, resp)
}