Reputation: 13
This is the code I am currently using:
func fetchOne(){
URLSession.shared.dataTask(with:apiURL!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { return }
do {
let allContactsData = try Data(contentsOf: self.apiURL!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["data"] as? [[String : Any]] {
for aObject in arrJSON {
self.followerUsername.append(aObject["username"] as! String)
self.followerFullName.append(aObject["full_name"] as! String)
}
}
// print(self.followerUsername)
// print(self.followerFullName)
} catch let error as NSError {
print(error)
}
}).resume()
}
How can I detect when the json has finished fetching all the info in data and then run a new function fetchTwo()
?
Upvotes: 0
Views: 1389
Reputation: 38833
If your method is asynchronous then you can add a completionHandler
to you function, like this:
func fetchOne(onCompletion: @escaping (Bool) -> Void, onError: @escaping (NSError) -> Void) {
URLSession.shared.dataTask(with:apiURL!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { return }
do {
let allContactsData = try Data(contentsOf: self.apiURL!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["data"] as? [[String : Any]] {
for aObject in arrJSON {
self.followerUsername.append(aObject["username"] as! String)
self.followerFullName.append(aObject["full_name"] as! String)
}
onCompletion(true)
}
// print(self.followerUsername)
// print(self.followerFullName)
} catch let error as NSError {
print(error)
onError(error)
}
}).resume()
}
Usage:
fetchOne(onCompletion: { (successful) in
print(successful)
fetchTwo()
}) { (error) in
print(error.domain)
}
If it´s synchronous then just do this:
func fetchOne(){
URLSession.shared.dataTask(with:apiURL!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { return }
do {
let allContactsData = try Data(contentsOf: self.apiURL!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["data"] as? [[String : Any]] {
for aObject in arrJSON {
self.followerUsername.append(aObject["username"] as! String)
self.followerFullName.append(aObject["full_name"] as! String)
}
}
// print(self.followerUsername)
// print(self.followerFullName)
fetchTwo()
} catch let error as NSError {
print(error)
}
}).resume()
}
Update:
fetchOne(onCompletion: { (successful) in
print(successful) // fetch one
fetchTwo(onCompletion: { (successful) in
print(successful) // fetch two
}) { (error) in
print(error.domain)
}
}) { (error) in
print(error.domain)
}
Upvotes: 1
Reputation: 142
Welcome to Swift :)
You are mixing synchronous and asynchronous code together.
When you call login you expect it to return an answer straight away of type [String : String].
But in your login method you then do a network call which can not return straight away...which is why the call to Alamofire.requesttakes a completion block as a parameter.
So...you need to change your login method so it:
does not return anything straight away (it can not do so...logging in requires us doing a network call remember) takes a completion block to invoke once login has succeeded. This can be done like so:
public func login(userName: String, password: String, loginCompletion: @escaping ([String : String]) -> ())
Welcome to Swift :)
You are mixing synchronous and asynchronous code together.
When you call login you expect it to return an answer straight away of type [String : String].
But in your login method you then do a network call which can not return straight away...which is why the call to Alamofire.requesttakes a completion block as a parameter.
So...you need to change your login method so it:
does not return anything straight away (it can not do so...logging in requires us doing a network call remember) takes a completion block to invoke once login has succeeded. This can be done like so:
public func login(userName: String, password: String, loginCompletion: @escaping ([String : String]) -> ()) Here we have a function that takes a userName of type String, a password of type String and a loginCompletion of type function that again takes a [String : String] dictionary as a parameter. Notice that the method does not return anything.
Now you can call your makeWebServiceCall almost as before:
let loginrequest = JsonRequests.loginRequest(userName: userName, password: password)
makeWebServiceCall(urlAddress: URL, requestMethod: .post, params: loginrequest, completion: { (JSON : Any) in
//Now we are ready, the login call has returned some data to you.
//You have an attribute named JSON of type Any, which you need to convert to [String : String], and then you can call loginCompletion with that, like so:
loginCompletion(yourConvertedDictionaryHere)
})
Here is the new login method in its completeness:
public func login(userName: String, password: String, loginCompletion: @escaping ([String : String]) -> ()) {
let loginrequest = JsonRequests.loginRequest(userName: userName, password: password)
makeWebServiceCall(urlAddress: URL, requestMethod: .post, params: loginrequest, completion: { (JSON : Any) in
//Now we are ready, the login call has returned some data to you.
//You have an attribute named JSON of type Any, which you need to convert to [String : String], and then you can call loginCompletion with that, like so:
loginCompletion(yourConvertedDictionaryHere)
})
}
Welcome to Swift :)
You are mixing synchronous and asynchronous code together.
When you call login you expect it to return an answer straight away of type [String : String].
But in your login method you then do a network call which can not return straight away...which is why the call to Alamofire.requesttakes a completion block as a parameter.
So...you need to change your login method so it:
does not return anything straight away (it can not do so...logging in requires us doing a network call remember) takes a completion block to invoke once login has succeeded. This can be done like so:
public func login(userName: String, password: String, loginCompletion: @escaping ([String : String]) -> ()) Here we have a function that takes a userName of type String, a password of type String and a loginCompletion of type function that again takes a [String : String] dictionary as a parameter. Notice that the method does not return anything.
Now you can call your makeWebServiceCall almost as before:
let loginrequest = JsonRequests.loginRequest(userName: userName, password: password) makeWebServiceCall(urlAddress: URL, requestMethod: .post, params: loginrequest, completion: { (JSON : Any) in //Now we are ready, the login call has returned some data to you.
//You have an attribute named JSON of type Any, which you need to convert to [String : String], and then you can call loginCompletion with that, like so: loginCompletion(yourConvertedDictionaryHere) }) Here is the new login method in its completeness:
public func login(userName: String, password: String, loginCompletion: @escaping ([String : String]) -> ()) { let loginrequest = JsonRequests.loginRequest(userName: userName, password: password) makeWebServiceCall(urlAddress: URL, requestMethod: .post, params: loginrequest, completion: { (JSON : Any) in //Now we are ready, the login call has returned some data to you.
//You have an attribute named JSON of type Any, which you need to convert to [String : String], and then you can call loginCompletion with that, like so:
loginCompletion(yourConvertedDictionaryHere)
})
} And then you call your login method like so:
retur.login(userName: "root", password: "admin01") { stringDictionary: [String : String] in
//here you have your stringDictionary which you can use as pleased
}
Hope that helps you.
Upvotes: 0