Escaping closure captures non-escaping parameter 'function' Xcode says - ios

I'm trying to perform a segue after two API requests are complete, and I have all the data I need. I'm trying do this because the requests take a bit long. However, when I tried to do something like this post, I got these errors:
1. Passing a non-escaping function parameter 'anotherFunc' to a call to a non-escaping function parameter can allow re-entrant modification of a variable
2. Escaping closure captures non-escaping parameter 'anotherFunc'
3. Escaping closure captures non-escaping parameter 'function'
I added comments where the errors show up. Here's my code:
func getUsernameRequest(function: () -> Void) {
// send an API request to get the userinfo
let url = "\(K.API.baseAPIEndpoint)/user"
let headers: HTTPHeaders = [...]
AF.request(url, headers: headers).responseDecodable(of: UserModel.self) { response in // this is where the #3 error shows up
if let value = response.value {
self.username = value.username
// and do other things
function()
} else {
offlineBanner()
}
}
}
func getMessagesRequest(function: (()->Void)->Void, anotherFunc:()->Void) {
let postDetailUrl = "\(K.API.baseAPIEndpoint)/posts/\(postArray[indexPath.row].id)"
let headers: HTTPHeaders = [...]
// send an API request to get all the associated messages
AF.request(postDetailUrl, headers: headers).responseDecodable(of: PostDetailModel.self) { response in // this is the #2 error shows up
if let value = response.value {
self.messages = value.messages
function(anotherFunc) // this is where the #1 error shows up
} else {
offlineBanner()
}
}
}
func performSegueToChat() -> Void {
self.performSegue(withIdentifier: K.Segue.GotoChat, sender: self)
}
getMessagesRequest(function: getUsernameRequest, anotherFunc: performSegueToChat)
Thank you in advance.

I did this the following code, and it works as I expected! (But they aren't too clean)
func getUsernameRequest(function: #escaping() -> Void) {
// send an API request to get the username
let url = "\(K.API.baseAPIEndpoint)/user"
AF.request(url, headers: headers).responseDecodable(of: GetUsernameModel.self) { response in
if let value = response.value {
self.username = value.username
function()
} else {
offlineBanner()
}
}
}
func getMessagesRequest(function: #escaping(#escaping()->Void)->Void, anotherFunc: #escaping()->Void) {
let postDetailUrl = "\(K.API.baseAPIEndpoint)/posts/\(postArray[indexPath.row].id)"
// send an API request to get all the associated messages and put them into messages array
AF.request(postDetailUrl, headers: headers).responseDecodable(of: PostDetailModel.self) { response in
if let value = response.value {
self.messages = value.messages
function(anotherFunc)
} else {
offlineBanner()
}
}
}
func performSegueToChat() -> Void {
self.performSegue(withIdentifier: K.Segue.GotoChat, sender: self)
}
getMessagesRequest(function: getUsernameRequest, anotherFunc: performSegueToChat)

Related

Refresh Token with Alamofire retry count and retry request swift

I am using Alamofire to integrate API calls, handling error code and specially status code error like 401 and 403. I have also created the getRefreshToken() function, if error comes it will refresh the token.
Problem I am facing about Alamofire.retryCount and repeat the request in the right way? I have seen different references but I cannot figure out How I integrate in my main method.
Updated: added getRefreshToken() code.
My Code:
#objc private func getDataFromWeb(params:NSMutableDictionary,
callback:#escaping (_ success:Bool, _ result:Any?)->(Bool)) -> Void {
var method = HTTPMethod.get
var encoding = URLEncoding.default as ParameterEncoding
if(params["Method"] as! String == "POST"){
method = HTTPMethod.post
encoding = Alamofire.JSONEncoding.default
}
Alamofire.request(url,
method:method,
parameters:pr,
encoding:encoding,
headers:[ "Accept":"application/json", "Authorization":"Bearer \(token ?? "")"])
.downloadProgress(closure: { (progress) in
//progress closure
})
.validate(statusCode: 200..<300)
.response { response in
print(response.error?.localizedDescription)
var code = response.response?.statusCode
if code == 401 || code == 403{
self.getRefreshToken() // calling refresh token method
} else {
if(callback(response.data?.count != 0, response.data)){
}
}
}
}
getRefreshToken Function:
func getRefreshToken() {
DataProvider.main.serviceLogin(username:User, password:Pass, firmNo: FirmId , callback:{success, result in
do{
if(success){
let model = try JSONDecoder().decode(Login.self, from: result as! Data)
if model.isSuccess == true {
DataProvider.main.token = model.token
}
return true
} else{
return false
}
}catch let e {
print(e)
return false
}
})
}
References:
https://stackoverflow.com/questions/58496713/retry-the-old-request-with-new-refresh-token-in-swift-alamofire
https://stackoverflow.com/questions/52287882/right-way-to-refresh-the-token

Return Bool in Alamofire closure

I use Swift 2 and Xcode 7.1.
I have a function who connect my users, but it will connect at my database with HTTP. I use Alamofire for execute this request. I want to know, from a view controller if the user is connected.
I have my function connect in a class. And i test connection in a ViewController.
Like this :
class user {
// ...
func connectUser(username: String, password: String){
let urlHost = "http://localhost:8888/project350705/web/app_dev.php/API/connect/"
let parametersSymfonyG = [
username, password
]
let url = UrlConstruct(urlHost: urlHost).setSymfonyParam(parametersSymfonyG).getUrl()
//var userArray = [String:AnyObject]()
Alamofire.request(.GET, url)
.responseString { response in
if let JSON = response.result.value {
var result = self.convertStringToDictionary(JSON)!
if result["status"] as! String == "success"{
let userArray = result["user"] as! [String:AnyObject]
userConnect = self.saveUser(userArray)
} else{
print("ERROR-CONNECTION :\n Status :\(result["status"]!)\n Code :\(result["code"]!)")
}
return ""
}
}
}
// ...
}
class MyViewController: UIViewController {
// ...
#IBAction func connect(sender: AnyObject?) {
// CONNECTION
User.connectUser(self.username.text!, password: self.password.text!)
// CHECK
if userConnect != nil {
print("connected")
}else{
print("NotConnected")
}
}
// ...
}
First solution : Return
To do so would require that my function returns a Boolean.
Only I can not use return.
Alamofire.request(.GET, url)
.responseString { response in
if let JSON = response.result.value {
var result = self.convertStringToDictionary(JSON)!
if result["status"] as! String == "success"{
let userArray = result["user"] as! [String:AnyObject]
userConnect = self.saveUser(userArray)
} else{
print("ERROR-CONNECTION :\n Status :\(result["status"]!)\n Code :\(result["code"]!)")
}
return "" // Unexpected non-void return value in void function
}
}
Second solution :
I can also test if the user has been logged, but before testing, I must wait for the function have finished loading.
users.connectUser(self.username.text!, password: self.password.text!)
// after
if userConnect != nil {
print("connected")
}else{
print("NotConnected")
}
I would prefer return a boolean. It will facilitate the processing.
Do you have a solution ?
I would suggest employing a completion handler in your connectUser method:
func connectUser(username: String, password: String, completion: #escaping (Bool) -> Void) {
// build the URL
// now perform request
Alamofire.request(url)
.responseString { response in
if let json = response.result.value, let result = self.convertStringToDictionary(json) {
completion(result["status"] as? String == "success")
} else {
completion(false)
}
}
}
You can then call it using:
users.connectUser(username.text!, password: password.text!) { success in
if success {
print("successful")
} else {
print("not successful")
}
}
// But don't use `success` here yet, because the above runs asynchronously
BTW, if your server is really generating JSON, you might use responseJSON rather than responseString, further streamlining the code and eliminating the need for convertStringToDictionary:
func connectUser(username: String, password: String, completion: #escaping (Bool) -> Void) {
// build the URL
// now perform request
Alamofire.request(url)
.responseJSON { response in
if let dictionary = response.result.value as? [String: Any], let status = dictionary["status"] as? String {
completion(status == "success")
} else {
completion(false)
}
}
}
If you've written your own server code to authenticate the user, just make sure you set the right header (because responseJSON not only does the JSON parsing for you, but as part of its validation process, it makes sure that the header specifies JSON body; it's good practice to set the header, regardless). For example in PHP, before you echo the JSON, set the header like so:
header("Content-Type: application/json");
The completion handler of your Alamofire.request method is asynchronous and it doesn't have a return type specified in its signature. Thats why you see an error when you provide a return statement in your completion handler closure.
You will have to split your request and response processing to separate methods and call the response processing method instead of using return statement.
Alamofire.request(.GET, url).responseString { response in
if let JSON = response.result.value {
var result = self.convertStringToDictionary(JSON)!
if result["status"] as! String == "success"{
let userArray = result["user"] as! [String:AnyObject]
userConnect = self.saveUser(userArray)
processSuccessResponse() //Pass any parameter if needed
} else{
print("ERROR-CONNECTION :\n Status :\(result["status"]!)\n Code :\(result["code"]!)")
processFailureResponse() //Pass any parameter if needed
}
}
}
func processSuccessResponse() {
//Process code for success
}
func processFailureResponse() {
//Process code for failure
}
My preferred way of doing this is to call a function in the completion handler. You can also set a boolean flag in order to check if the user is connected at any given time.
func connectUser(username: String, password: String, ref: MyClass) {
Alamofire.request(.GET, url)
.responseString { response in
var userIsConnected = false
if let JSON = response.result.value {
var result = self.convertStringToDictionary(JSON)!
if result["status"] as! String == "success"{
let userArray = result["user"] as! [String:AnyObject]
userConnect = self.saveUser(userArray)
userIsConnected = true
} else {
print("ERROR-CONNECTION :\n Status :\(result["status"]!)\n Code :\(result["code"]!)")
}
} else {
print("Response result nil")
}
ref.finishedConnecting(userIsConnected)
}
}
}
class MyClass {
var userIsConnected = false
func startConnecting() {
connectUser(username, password: password, ref: self)
}
func finishedConnecting(success: Bool) {
userIsConnected = success
... post-connection code here
}
}

Data not being returned in Swift function iOS [duplicate]

This question already has answers here:
I won't be able to return a value with Alamofire in Swift
(3 answers)
Closed 7 years ago.
Possibly this could be a misunderstanding that I have in Swift. I'm new to the language and my background is in Perl, which makes me feel like swift is acting differently.
I have 2 files. ViewController.swift and APICalls.swift. In viewcontroller I have a function for a button. In this function I'm making a call to another function in the APICalls. When I do, my println() in the APICalls is printing the correct data, however, it's doing so after my println() in the button function.
Viewcontroller.swift
#IBAction func buttonStuff(sender: AnyObject) {
var api = APICalls()
var token:String
token = api.TEST("letmein")
println("\ntokenDidLOAD = \(token)\n")
}
APICalls.swift
class APICalls {
func TEST(command: String) -> (String) {
var token:String = ""
// Form URL-Encoded Body
let bodyParameters = [
"COMMAND":command,
]
let encoding = Alamofire.ParameterEncoding.URL
// Fetch Request
Alamofire.request(.POST, "http://api.com/?v=1", parameters: bodyParameters, encoding: encoding)
.validate(statusCode: 200..<300)
.responseJSON{(request, response, data, error) in
if (error == nil)
{
let json = JSON(data!)
token = json["TOKEN"].string!
println("jsonAPI = \(json) \n\n")
}
else
{
println("HTTP HTTP Request failed: \(error)")
}
}
return token
}
}
Here is my output
tokenDidLOAD =
jsonAPI = {
"STATUS" : "OK",
"TOKEN" : "698798765432134654",
}
I don't understand why 'tokenDidLOAD' is printing first before the jsonAPI.
Because the request that you make is asynchronous. You first return the token that is not present yet and only after that the request is actually finished. You don't need to get the token as TEST function's return value. Your TEST should be like this:
func TEST(command: String, completion:(String)->()) {
var token:String = ""
// Form URL-Encoded Body
let bodyParameters = [
"COMMAND":command,
]
let encoding = Alamofire.ParameterEncoding.URL
// Fetch Request
Alamofire.request(.POST, "http://api.com/?v=1", parameters: bodyParameters, encoding: encoding)
.validate(statusCode: 200..<300)
.responseJSON{(request, response, data, error) in
if (error == nil)
{
let json = JSON(data!)
token = json["TOKEN"].string!
println("jsonAPI = \(json) \n\n")
completion(token)
}
else
{
println("HTTP HTTP Request failed: \(error)")
}
}
Then you call it:
api.TEST("letmein", {(newToken : String) in
token = newToken
println("\ntokenDidLOAD = \(token)\n")
})
Because this println("jsonAPI = \(json) \n\n") is in side the block statement, which will run as soon request get complete, till then compiler will run next jobs means your println("\ntokenDidLOAD = \(token)\n"). Block will Run on another subthread.
If you want to print println("\ntokenDidLOAD = \(token)\n") when request get complete, then use oncomplete based block.
May this help you bit a way.
Alamofire fetches data asynchronously by default, which is the desired behaviour for pretty much every website or app. By the time the function reaches the return token the request might not have been finished yet.
One idea is to pass in a closure to your API call to be executed once the request is finished:
func TEST(command: String, closure: (JSON) -> ()) -> (String) {
var token:String = ""
// Form URL-Encoded Body
let bodyParameters = [
"COMMAND":command,
]
let encoding = Alamofire.ParameterEncoding.URL
// Fetch Request
Alamofire.request(.POST, "http://api.com/?v=1", parameters: bodyParameters, encoding: encoding)
.validate(statusCode: 200..<300)
.responseJSON{(request, response, data, error) in
if (error == nil)
{
let json = JSON(data!)
token = json["TOKEN"].string!
println("jsonAPI = \(json) \n\n")
closure(json)
}
else
{
println("HTTP HTTP Request failed: \(error)")
}
}
return token
}
Then you could call it via:
api.TEST("letmein") { json in
let token = json["TOKEN"].stringValue
println("\ntokenDidLOAD = \(token)\n")
}
The closure accepts an object of type JSON as a parameter, which you can use to do whatever you want with the json inside.
Also one thing to note: I'm assuming you're using the SwiftyJSON library. Before, you called json["TOKEN"].string!. This force-unwraps an optional, which should be avoided generally (unless you're absolutely sure it has a value). In such a case, you would want to use json["TOKEN"].stringValue instead. It returns String instead of String?

Chain multiple Alamofire requests

I'm looking for a good pattern with which I can chain multiple HTTP requests. I want to use Swift, and preferrably Alamofire.
Say, for example, I want to do the following:
Make a PUT request
Make a GET request
Reload table with data
It seems that the concept of promises may be a good fit for this. PromiseKit could be a good option if I could do something like this:
NSURLConnection.promise(
Alamofire.request(
Router.Put(url: "http://httbin.org/put")
)
).then { (request, response, data, error) in
Alamofire.request(
Router.Get(url: "http://httbin.org/get")
)
}.then { (request, response, data, error) in
// Process data
}.then { () -> () in
// Reload table
}
but that's not possible or at least I'm not aware of it.
How can I achieve this functionality without nesting multiple methods?
I'm new to iOS so maybe there's something more fundamental that I'm missing. What I've done in other frameworks such as Android is to perform these operations in a background process and make the requests synchronous. But Alamofire is inherently asynchronous, so that pattern is not an option.
Wrapping other asynchronous stuff in promises works like this:
func myThingy() -> Promise<AnyObject> {
return Promise{ fulfill, reject in
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"]).response { (_, _, data, error) in
if error == nil {
fulfill(data)
} else {
reject(error)
}
}
}
}
Edit: Nowadays, use: https://github.com/PromiseKit/Alamofire-
I wrote a class which handles a chain of request one by one.
I created a class RequestChain wich takes Alamofire.Request as parameter
class RequestChain {
typealias CompletionHandler = (success:Bool, errorResult:ErrorResult?) -> Void
struct ErrorResult {
let request:Request?
let error:ErrorType?
}
private var requests:[Request] = []
init(requests:[Request]) {
self.requests = requests
}
func start(completionHandler:CompletionHandler) {
if let request = requests.first {
request.response(completionHandler: { (_, _, _, error) in
if error != nil {
completionHandler(success: false, errorResult: ErrorResult(request: request, error: error))
return
}
self.requests.removeFirst()
self.start(completionHandler)
})
request.resume()
}else {
completionHandler(success: true, errorResult: nil)
return
}
}
}
And I use it like this
let r1 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in
print("1")
}
let r2 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in
print("2")
}
let r3 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in
print("3")
}
let chain = RequestChain(requests: [r1,r2,r3])
chain.start { (success, errorResult) in
if success {
print("all have been success")
}else {
print("failed with error \(errorResult?.error) for request \(errorResult?.request)")
}
}
Importent is that you are telling the Manager to not execute the request immediately
let manager = Manager.sharedInstance
manager.startRequestsImmediately = false
Hope it will help someone else
Swift 3.0 Update
class RequestChain {
typealias CompletionHandler = (_ success:Bool, _ errorResult:ErrorResult?) -> Void
struct ErrorResult {
let request:DataRequest?
let error:Error?
}
fileprivate var requests:[DataRequest] = []
init(requests:[DataRequest]) {
self.requests = requests
}
func start(_ completionHandler:#escaping CompletionHandler) {
if let request = requests.first {
request.response(completionHandler: { (response:DefaultDataResponse) in
if let error = response.error {
completionHandler(false, ErrorResult(request: request, error: error))
return
}
self.requests.removeFirst()
self.start(completionHandler)
})
request.resume()
}else {
completionHandler(true, nil)
return
}
}
}
Usage Example Swift 3
/// set Alamofire default manager to start request immediatly to false
SessionManager.default.startRequestsImmediately = false
let firstRequest = Alamofire.request("https://httpbin.org/get")
let secondRequest = Alamofire.request("https://httpbin.org/get")
let chain = RequestChain(requests: [firstRequest, secondRequest])
chain.start { (done, error) in
}
You have multiple options.
Option 1 - Nesting Calls
func runTieredRequests() {
let putRequest = Alamofire.request(.PUT, "http://httpbin.org/put")
putRequest.response { putRequest, putResponse, putData, putError in
let getRequest = Alamofire.request(.GET, "http://httpbin.org/get")
getRequest.response { getRequest, getResponse, getData, getError in
// Process data
// Reload table
}
}
}
This is definitely the approach I would recommend. Nesting one call into another is very simple and is pretty easy to follow. It also keeps things simple.
Option 2 - Splitting into Multiple Methods
func runPutRequest() {
let putRequest = Alamofire.request(.PUT, "http://httpbin.org/put")
putRequest.response { [weak self] putRequest, putResponse, putData, putError in
if let strongSelf = self {
// Probably store some data
strongSelf.runGetRequest()
}
}
}
func runGetRequest() {
let getRequest = Alamofire.request(.GET, "http://httpbin.org/get")
getRequest.response { [weak self] getRequest, getResponse, getData, getError in
if let strongSelf = self {
// Probably store more data
strongSelf.processResponse()
}
}
}
func processResponse() {
// Process that data
}
func reloadData() {
// Reload that data
}
This option is less dense and splits things up into smaller chunks. Depending on your needs and the complexity of your response parsing, this may be a more readable approach.
Option 3 - PromiseKit and Alamofire
Alamofire can handle this pretty easily without having to pull in PromiseKit. If you really want to go this route, you can use the approach provided by #mxcl.
Here is another way to do this (Swift 3, Alamofire 4.x) using a DispatchGroup
import Alamofire
struct SequentialRequest {
static func fetchData() {
let authRequestGroup = DispatchGroup()
let requestGroup = DispatchGroup()
var results = [String: String]()
//First request - this would be the authentication request
authRequestGroup.enter()
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: FIRST Request")
results["FIRST"] = response.result.description
if response.result.isSuccess { //Authentication successful, you may use your own tests to confirm that authentication was successful
authRequestGroup.enter() //request for data behind authentication
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: SECOND Request")
results["SECOND"] = response.result.description
authRequestGroup.leave()
}
authRequestGroup.enter() //request for data behind authentication
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: THIRD Request")
results["THIRD"] = response.result.description
authRequestGroup.leave()
}
}
authRequestGroup.leave()
}
//This only gets executed once all the requests in the authRequestGroup are done (i.e. FIRST, SECOND AND THIRD requests)
authRequestGroup.notify(queue: DispatchQueue.main, execute: {
// Here you can perform additional request that depends on data fetched from the FIRST, SECOND or THIRD requests
requestGroup.enter()
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: FOURTH Request")
results["FOURTH"] = response.result.description
requestGroup.leave()
}
//Note: Any code placed here will be executed before the FORTH request completes! To execute code after the FOURTH request, we need the request requestGroup.notify like below
print("This gets executed before the FOURTH request completes")
//This only gets executed once all the requests in the requestGroup are done (i.e. FORTH request)
requestGroup.notify(queue: DispatchQueue.main, execute: {
//Here, you can update the UI, HUD and turn off the network activity indicator
for (request, result) in results {
print("\(request): \(result)")
}
print("DEBUG: all Done")
})
})
}
}
Details
Alamofire 4.7.2
PromiseKit 6.3.4
Xcode 9.4.1
Swift 4.1
Full Sample
NetworkService
import Foundation
import Alamofire
import PromiseKit
class NetworkService {
static fileprivate let queue = DispatchQueue(label: "requests.queue", qos: .utility)
fileprivate class func make(request: DataRequest) -> Promise <(json: [String: Any]?, error: Error?)> {
return Promise <(json: [String: Any]?, error: Error?)> { seal in
request.responseJSON(queue: queue) { response in
// print(response.request ?? "nil") // original URL request
// print(response.response ?? "nil") // HTTP URL response
// print(response.data ?? "nil") // server data
//print(response.result ?? "nil") // result of response serialization
switch response.result {
case .failure(let error):
DispatchQueue.main.async {
seal.fulfill((nil, error))
}
case .success(let data):
DispatchQueue.main.async {
seal.fulfill(((data as? [String: Any]) ?? [:], nil))
}
}
}
}
}
class func searchRequest(term: String) -> Promise<(json: [String: Any]?, error: Error?)>{
let request = Alamofire.request("https://itunes.apple.com/search?term=\(term.replacingOccurrences(of: " ", with: "+"))")
return make(request: request)
}
}
Main func
func run() {
_ = firstly {
return Promise<Void> { seal in
DispatchQueue.global(qos: .background).asyncAfter(deadline: DispatchTime.now() + .seconds(2)) {
print("1 task finished")
DispatchQueue.main.async {
seal.fulfill(Void())
}
}
}
}.then {
return NetworkService.searchRequest(term: "John").then { json, error -> Promise<Void> in
print("2 task finished")
//print(error ?? "nil")
//print(json ?? "nil")
return Promise { $0.fulfill(Void())}
}
}.then {_ -> Promise<Bool> in
print("Update UI")
return Promise { $0.fulfill(true)}
}.then { previousResult -> Promise<Void> in
print("previous result: \(previousResult)")
return Promise { $0.fulfill(Void())}
}
}
Result
You can use the when method in PromiseKit to attach/append as many calls you want.
Here's an example from PromiseKit docs:
firstly {
when(fulfilled: operation1(), operation2())
}.done { result1, result2 in
//…
}
It worked perfectly for me and it's a much cleaner solution.
Call itself infinitely and DEFINE END CONDITION.
urlring for API link and Dictionary for json
WE may construct the queue model or delegate
func getData(urlring : String , para : Dictionary<String, String>) {
if intCount > 0 {
Alamofire.request( urlring,method: .post, parameters: para , encoding: JSONEncoding.default, headers: nil) .validate()
.downloadProgress {_ in
}
.responseSwiftyJSON {
dataResponse in
switch dataResponse.result {
case .success(let json):
print(json)
let loginStatus : String = json["login_status"].stringValue
print(loginStatus)
if loginStatus == "Y" {
print("go this")
print("login success : int \(self.intCount)")
self.intCount-=1
self.getData(urlring: urlring , para : para)
}
case .failure(let err) :
print(err.localizedDescription)
}
}
}else{
//end condition workout
}
}

Swift: How to pass closure argument from a class method to a function in the class

I have this class defined in my app to handle requests to my backend
class BackendService {
// Retrieves user chat channels
class func getChatChannels(success:(response: Response)->(), failure: (response:Response)->()) {
let chatsURL = baseURL + "/chats"
performRequestWith(success, failure: failure, url: chatsURL, parameters: nil)
}
func performRequestWith(success:(response: Response)->(), failure: (response: Response) -> (), url: String, parameters: String?) {
var manager = Alamofire.Manager.sharedInstance
let keychain = Keychain(service:"com.domain.app")
let token = keychain.get("token")
if let token = token {
manager.session.configuration.HTTPAdditionalHeaders = ["Authorization": "Bearer \(token)"]
manager.request(.GET, url, parameters:nil).responseJSON { (req, res, json, err) in
if(err != nil) {
var response = Response()
response.error = err
failure(response: response)
} else {
var response = Response()
if let httpStatus = HTTPStatus(rawValue: res!.statusCode) {
response.httpStatus = httpStatus
}
response.payload = JSON(json!)
success(response: response)
}
}
}
}
}
I am trying to pass the callback/closure arguments that getChatChannels receives to performRequestWith. In performRequestWith(success, failure: failure, url: chatsURL, parameters: nil) I am getting Extra argument 'failure' in call
I have little experience with Swift and I am clearly doing something awfully wrong here. Some help would much appreciated.
There is no issue with your method calling code.
The issue is you are calling a instance method from a class method.
Either you should change both methods to class method, like:
class func getChatChannels(success:(response: Response)->(), failure: (response:Response)->())
{
let chatsURL = baseURL + "/chats"
performRequestWith(success, failure: failure, url: chatsURL, parameters: nil)
}
class func performRequestWith(success:(response: Response)->(), failure: (response: Response) -> (), url: String, parameters: String?)
{
// Your code
}
or Change both to instance method, like:
func getChatChannels(success:(response: Response)->(), failure: (response:Response)->())
{
let chatsURL = baseURL + "/chats"
performRequestWith(success, failure: failure, url: chatsURL, parameters: nil)
}
func performRequestWith(success:(response: Response)->(), failure: (response: Response) -> (), url: String, parameters: String?)
{
// Your code
}
Another option is create an instance of the class inside the class method and using that call the instance method.

Resources