i'm trying to write a method to return a json response from an API as a string. This is my code:
func authenticateUser(completionHandler: (responseObject: String?, error: NSError?) -> ()) {
makeCall(completionHandler: completionHandler)
}
func makeCall(completionHandler: (responseObject: String?, error: NSError?) -> ()) {
Alamofire.request(.GET, loginUrlString)
.authenticate(user: "x", password: "y")
.responseString { request, response, responseObject, error in
completionHandler(responseObject: responseObject as? String, error: error)
}
}
I can't compile it, the makeCall call in authenticateUser method says "Extraneous argument label 'completionHandler' in call.
I can't see whats wrong in my code?
Try just calling makeCall(completionHandler).
From the error message, I would guess that that is what it is complaining about. Swift function label use often seems inconsistent and confusing.
Related
I have a function that looks like this, and I have tried to add a completionHandler in the code below:
func getValueFromAPI(completionHandler: (_ result: Bool) -> Void){
apii.getVehicle(id!).done {
(vehicle: Vehicle) -> Void in
print("ggg.state: \(vehicle.state!)")
print("ggg.state: \(vehicle.displayName!)")
apii.getAllData(vehicle).done { (extendedVehicle: VehicleExtended) in
let entryBattery = (extendedVehicle.chargeState?.batteryLevel)!
let entryCarState = (extendedVehicle.state)!
print("entryBattery: \(entryBattery)")
print("entryCarState: \(entryCarState)")
completionHandler(true)
}.catch { (error) in
print("ERROOOOR: \(error)")
}
}.catch { error in
print("errorr: \(error)")
}
}
I have already tried to add a complete handler, but I get the following error on these lines:
Line: apii.getVehicle(id!).done {
Error: Escaping closure captures non-escaping parameter 'completionHandler'
Line: apii.getAllData(vehicle).done { (extendedVehicle: VehicleExtended) in
Error: Escaping closure captures non-escaping parameter 'completionHandler'
What am I doing wrong here, and how can I fix this?
I am using Swift 5.
You need to declare your completionHandler to be an escaping closure. E.g.:
func getValueFromAPI(completionHandler: #escaping (Bool) -> Void) {
...
}
Note the #escaping qualifier.
I'm trying to using AFNetworking in Swift and my code is:
self.get(urlString, parameters: parameters, progress: { (progress: Progress) in
print(progress)
}, success: { (task: URLSessionDataTask, result: AnyObject) in
print(result)
}) { (task: URLSessionDataTask, error: Error) in
print(error)
}
Then the compiler throws an error:
Extra argument 'progress' in call.
I tried to assign nil to it, but the error is still there.
What should I do if I don't want to change to Alamofire?
There are several type mismatches in your code (URLSessionDataTask instead of URLSessionDataTask?, AnyObject instead of Any? etc.)
You can get rid of those easily, since closures don't need to have external type specifiers in Swift. Remove all instances of those, e.g. : Progress, : URLSessionDataTask...
self.get(urlString, parameters: parameters, progress: { (progress) in
print(progress)
}, success: { (task, result) in
print(result)
}) { (task, error) in
print(error)
}
Read more about Swift closure syntax here.
I have these two methods in my API class to get data from an API:
func authenticateUser(completionHandler: (responseObject: String?, error: NSError?) -> ()) {
makeAuthenticateUserCall(completionHandler)
}
func makeAuthenticateUserCall(completionHandler: (responseObject: String?, error: NSError?) -> ()) {
Alamofire.request(.GET, loginUrlString)
.authenticate(user: "a", password: "b")
.responseString { request, response, responseString, responseError in
completionHandler(responseObject: responseString as String!, error: responseError)
}
}
Then in another class i use the following code to access the data:
API().authenticateUser{ (responseObject, error) in
println(responseObject)
}
The code is working but i don't understand it completely.
func authenticateUser has the parameter completionHandler: (responseObject: String?, error: NSError?) -> (), is this a reference to the completionHandler method? or is it an object? whats the purpose of -> ()?
When i call the authenticateUser func, how do i actually access the response? There is no return in any of my api funcs, the funcname{(parameter, parameter) in .. } syntax seems really strange.
completionHandler is a closure parameter. As Swift documentation says:
Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
So, what a closure is used for is to add some functionality of your own that you want to add to the execution of your function.
In your case, you call authenticateUser and you pass a closure that receives (responseObject, error) and executes println(responseObject). authenticateUser() receives your closure under the completionHandler parameter and it then calls makeAuthenticateUserCall() passing your completionHandler closure to it.
Then again, looking at the definition you can see func makeAuthenticateUserCall(completionHandler: (responseObject: String?, error: NSError?) -> ()) that means that like authenticateUser() makeAuthenticateUserCall() is a function that receives a closure as a parameter, under the name of completionHandler. makeAuthenticateUserCall() makes a network request using AlamoFire and you capture the response under a closure again that you pass as parameter of the responseString() method. So you have:
//here you call authenticateUser with a closure that prints responseObject
API().authenticateUser{ (responseObject, error) in
println(responseObject)
}
Then:
//authenticateUser receives your closure as a parameter
func authenticateUser(completionHandler: (responseObject: String?, error: NSError?) -> ()) {
//it passes your closure to makeAuthenticateUserCall
makeAuthenticateUserCall(completionHandler)
}
//makeAuthenticateUserCall receives your closure
func makeAuthenticateUserCall(completionHandler: (responseObject: String?,
error: NSError?) -> ()) {
Alamofire.request(.GET, loginUrlString)
.authenticate(user: "a", password: "b")
//here you pass a new closure to the responseString method
.responseString { request, response, responseString, responseError in
//in this closure body you call your completionHandler closure with the
//parameters passed by responseString and your code gets executed
//(that in your case just prints the responseObject)
completionHandler(responseObject: responseString as String!, error: responseError)
}
}
For more information read the documentation: Swift Closures
I'm using Alamofire, with ObjectMapper, things were so smooth before upgrading to Swift 2.0, now,
For the following signature:
public func responseArray<T: Mappable>(completionHandler: ([T]?, ErrorType?) -> Void) -> Self
I'm calling
Alamofire.request(.GET, URL, parameters: nil)
.responseArray { (response: [MyObject]?, error: NSError?) in
}
and getting the following error:
Cannot invoke 'responseArray' with an argument list of type
(([MyObject]?, NSError?) -> ())
Any help will be super appreciated.
try this.
Alamofire.request(.GET, URL, parameters: nil)
.responseArray { (response: [MyObject]?, error) in
//your process
}
In one of my app I have used block for webservice calling and getting response. Now I want to write this app in swift, but I am getting trouble to use blocks/Closure in Swift.
Here is my objective C code which I want to migrate in swift:
calling a class method of Communicator
[[Communicator sharedInstance]callWebService:WS_LOGIN withMethod:POST_METHOD andParams:params showLoader:YES completionBlockSuccess:^(id obj) {
//Do play with data
}completionBlockFailiure:^(id obj) {
//Show alert with error
}];
in communicator class
-(void)callWebService:(NSString *)serviceName withMethod:(NSString *)methodName andParams:(NSDictionary *)params showLoader:(BOOL)showLoader completionBlockSuccess:(void (^)(id))aBlock completionBlockFailiure:(void (^)(id))aFailBlock
{
if (showLoader) {
// show loader
}
[self performRequestWithServiceName:serviceName method:methodName andParams:params successblock:aBlock failureblock:aFailBlock];
}
- (void)performRequestWithServiceName:(NSString *)serviceName method:(NSString*)methodName andParams:(NSDictionary*)params
successblock:(void (^)(id obj))successBlock
failureblock:(void (^)(id obj))failBlock {
if(callSuceess){
successBlock(#"Success");
}else{
successBlock(nil);
}
}
For Swift. Use AnyObject for id objc type.
func callWebservice (serviceName: String, withMethod method: String, andParams params: NSDictionary, showLoader loader: Bool, completionBlockSuccess aBlock: ((AnyObject) -> Void), andFailureBlock failBlock: ((AnyObject) -> Void)) {
if loader {
// Show loader
}
performRequestWithServiceName(serviceName, method: method, andParams: params, success: aBlock, failure: failBlock)
}
func performRequestWithServiceName(serviceName: String, method methodName: String, andParams params: NSDictionary, success successBlock: ((AnyObject) -> Void), failure failureBlock: ((AnyObject) -> Void)) {
if callSuceess {
successBlock("Success")
}else {
successBlock(nil)
}
}
UPDATE: An example when you want call web service. See code below
callWebservice("your-service-name", withMethod: "your-method", andParams: ["your-dic-key": "your dict value"], showLoader: true/*or false*/, completionBlockSuccess: { (success) -> Void in
// your successful handle
}) { (failure) -> Void in
// your failure handle
}
Your code might look like this:
func callWebService(serviceName: String, method: String, params: [String : AnyObject], showLoader: Bool, success: (responseObject: AnyObject) -> Void, failure: (responseObject: AnyObject) -> Void) {
if showLoader {
// show loader
}
performRequest(serviceName, method: method, params: params, success: success, failure: failure)
}
func performRequest(serviceName: String, method: String, params: [String : AnyObject], success: (responseObject: AnyObject) -> Void, failure: (responseObject: AnyObject) -> Void) {
}
I replaced NSDictionary with [String : AnyObject]. If you can replace any of the uses of AnyObject with more specific types, your code will be cleaner and more stable.
For Swift Closures we have to use ( ) -> ( )
For example:
func yourFunction(success: (response: AnyObject!) -> Void, failure: (error: NSError?) -> Void) {
}
You can call it as:
yourFunction({(response) -> Void in
// Success
}) { (error) -> Void in
// Handle Errors
}
Hope it will help you to create Closures with your requirements.
In the communicator class the method that cals the webservice would be defined something like this depending on the type of object you want to return
func performRequest(serviceName: NSString, methodName: NSString,paramaters:NSDictionary, successblock: (String)->(), failureBlock: () -> ()) {
if(callSuccess) {
successblock("Success")
} else {
failureBlock()
}
We define the success and failure blocks types as by their function signatures in the case above success is defined as a method that takes a string as an input parameter and returns nothing so we can then call successBlock passing in a string. The failure block is defined above as a block that takes no parameters and returns nothing.
To call this method
func callWebService(serviceName: NSString, method: NSString and parameters: NSDictionary, showLoader: Bool, completionBlockSuccess:(String) -> (), completionBlockFailiure:() -> ()) {
if (showLoader) {
// show loader
}
performRequest(serviceName: serviceName, methodName: method, parameters, successBlock:completionBlockSuccess, failureBlock: completionBlockFailiure)
}
Finally to call this
Communicator.sharedInstance().callWebService(serviceName: WS_LOGIN , method: POST_METHOD and parameters: params, showLoader: true, completionBlockSuccess:{ returnedString in
//Do play with data
}, completionBlockFailiure:{
//Show alert with error
})
For the completion block we define a variable returnedString to allow us to manipulate that input parameter (in the above example it would be the string "Success"). I assume your data is not just returning a string though so you will probably need to play around with they type depending on what your service returns.
Also here I tried to match your method signatures by using NSString and NSDictionary though depending on your needs the Swift equivalents String and [String: AnyObject] could be more appropriate.
func processingWithAnyObject(input: String, completion: #escaping (_ result: AnyObject) -> Void) {
...
completion(response.result.value! as AnyObject)
}
processingWithAnyObject("inputString") {
(result: AnyObject) in
print("back to caller: \(result)")
}