Returning a value from a function with Alamofire and SwiftyJson
An example of a completion handler for your getMenu function, assuming menu
is the value you want to "return":
class MenuManager {
// the handler takes an EKMenu argument
class func getMenu(menu_id: Int, completionHandler: (menu: EKMenu) -> ()) {
let url="https://www.domain.com/arc/v1/api/menus/\(menu_id)/mobile"
Alamofire.request(.GET, url).responseJSON() {
(_, _, data, _) in
println("within menu request")
var json=JSON(data!)
var menu=EKMenu()
menu.name=json["menu"]["name"].stringValue
for (key, subJson) in json["menu"]["menu_headers"]{
EKMenu.processMenuHeaders(subJson)
}
// wrap the resulting EKMenu in the handler
completionHandler(menu)
}
}
class func processMenuHeaders(menu_header: JSON){
let mh_name=menu_header["name"].stringValue
println("mh_name: \(mh_name)")
for (key, subJson) in menu_header["menu_headers"]{
EKMenu.processMenuHeaders(subJson)
}
}
}
MenuManager.getMenu(42, completionHandler: { menu in
// here the handler gives you back the value
println(menu)
})
Alamofire and SwiftyJSon get value outside request function
You can't subscript with Any
and after you converting JSON
to [String:Any]
if you are trying .stringValue
with subscripting Dictionary
then Dictionary
doesn't have any property stringValue
you are mixing two things here SwiftyJSON
and Swift native type. I will access your JSON
response this way.
First get clear about how you get value of ubus_rpc_session
from your JSON
response. You can't directly get value of ubus_rpc_session
from your JSON
response because it is inside the 2nd object in your result
array,so to get the ubus_rpc_session
try like this way.
retur.login(userName: userName.text!, password: password.text!) { (json) in
print(json)
if let dic = json as? [String:Any], let result = dic["result"] as? [Any],
let subDic = result.last as? [String:Any],
let session = subDic["ubus_rpc_session"] as? String {
print(session)
}
}
If you want to work with SwiftyJSON
then you can get value of ubus_rpc_session
this way.
retur.login(userName: userName.text!, password: password.text!) { (json) in
print(json)
let jsonDic = JSON(json)
print(jsonDic["result"][1]["ubus_rpc_session"].stringValue)
}
How to return value from Alamofire
As mattt points out, Alamofire is returning data asynchronously via a “completion handler” pattern, so you must do the same. You cannot just return
the value immediately, but you instead want to change your method to not return anything, but instead use a completion handler closure pattern.
Nowadays, that might look like:
func getOrders(completionHandler: @escaping (Result<[String: Any]>) -> Void) {
performRequest("orders", completion: completionHandler)
}
func performRequest(_ section: String, completion: @escaping (Result<[String: Any]>) -> Void) {
let url = baseURL.appendingPathComponent(section)
let params = ["consumer_key": "key", "consumer_secret": "secret"]
Alamofire.request(url, parameters: params)
.authenticate(user: consumerKey, password: consumerSecret)
.responseJSON { response in
switch response.result {
case .success(let value as [String: Any]):
completion(.success(value))
case .failure(let error):
completion(.failure(error))
default:
fatalError("received non-dictionary JSON response")
}
}
}
Then, when you want to call it, you use this completion
closure parameter (in trailing closure, if you want):
api.getOrders { result in
switch result {
case .failure(let error):
print(error)
case .success(let value):
// use `value` here
}
}
// but don't try to use the `error` or `value`, as the above closure
// has not yet been called
//
Return a value in a nested JSON array, using Alamofire and Swift
You can use Decodable
to get the desired result.
struct RootResponse: Decodable {
let destinationAddresses, originAddresses: [String]
let rows: [Rows]
let status: String
}
struct Rows: Decodable {
let elements: [Elements]
}
struct Elements: Decodable {
let distance, duration: Details
let status: String
}
struct Details: Decodable {
let text, value: String
}
This will be your model file and once you have added it then you can go back to your function and use it as:
func distanceMatrix(startLocation: String, endLocation: String) {
let myOrigin = startLocationTFText
let myDestination = destinationLocationTFText
let url = "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=\(myOrigin)&destinations=\(myDestination)&key=API_Key"
let encodedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
AF.request(encodedUrl!).responseJSON { response in
print(response.request as Any)
print(response.response as Any)
print(response.data as Any)
print(response.result as Any)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
guard let json = try? decoder.decode(RootResponse.self, from: response.data) else { print("Unable to parse JSON"); return }
print(json)
print(json.rows.first?.elements.first?.distance.value) // This is how you can get the value, but it will be better to safely unwrap them and I have also used first? to get the first object but this is an array and you can always use a for loop for further purpose
}
Alamofire request with SwiftyJSON parameters
I found the solution by myself:
let params = ["customObjects": customObjects.map({$0.toDictionary()})]
And here the toDictionary() func inside my CustomObject:
func toDictionary() -> [String: Any] {
let dict: [String: Any] = [
"exampleKey": "exampleValue",
"exampleKey2": "exampleValue2"
]
return dict
}
I guess this is because you can setup Alamofire with encoding: JSONEncoding.default
.
Return value from Alamofire request in Swift 2.2
Take a look at the most frequently asked questions on the site. Your problem is one of timing – if you were to print both of the results inside the completion handler, and outside, you will see that the function returns well before the completion handler executes. They are asynchronous, and the function call itself is gone before the results come back
Related Topics
Spritekit Physics in Swift - Ball Slides Against Wall Instead of Reflecting
Check If Key Exists in Dictionary of Type [Type:Type]
Use Reserved Keyword a Enum Case
Ios11 Swift Silent Push (Background Fetch, Didreceiveremotenotification) Is Not Working Anymore
Convert Swift Array to Dictionary With Indexes
What Is the Real Benefit of Using Raycast in Arkit and Realitykit
Default Value For Optional Generic Parameter in Swift Function
In Swift 3, How to Calculate the Factorial When the Result Becomes Too High
Swift3 Optionals Chaining in If Conditions Bug
Projecting the Arkit Face Tracking 3D Mesh to 2D Image Coordinates
Swiftui Hierarchical Picker With Dynamic Data Crashes
How String Comparison Happens in Swift
Can You Override Between Extensions in Swift or Not? (Compiler Seems Confused!)
Swift Spritekit Adding Button Programmatically
Type Conversion When Using Protocol in Swift
How to Save Data from Cloud Firestore to a Variable in Swift