I am using Alamofire for basic networking. Here is my problem. I have a class
class User {
var name:String?
var company:String
init () {
//
manager = Alamofire.Manager(configuration: configuration)
}
func details () {
//first we login, if login is successful we fetch the result
manager.customPostWithHeaders(customURL!, data: parameter, headers: header)
.responseJSON { (req, res, json, error) in
if(error != nil) {
NSLog("Error: \(error)")
}
else {
NSLog("Success: \(self.customURL)")
var json = JSON(json!)
println(json)
self.fetch()
println("I fetched correctly")
}
}
func fetch() {
manager.customPostWithHeaders(customURL!, data: parameter, headers: header)
.responseJSON { (req, res, json, error) in
if(error != nil) {
NSLog("Error: \(error)")
}
else {
NSLog("Success: \(self.customURL)")
var json = JSON(json!)
println(json)
//set name and company
}
}
}
My problem is if I do something like
var my user = User()
user.fetch()
println("Username is \(user.name)")
I don’t get anything on the console for user.name. However if I put a break point, I see that I get username and company correctly inside my fetch function. I think manager runs in separate non blocking thread and doesn’t wait. However I really don’t know how can I initialize my class with correct data if I can’t know whether manager finished successfully. So how can I initialize my class correctly for immediate access after all threads of Alamofire manager did their job?
You don't want to do the networking inside your model object. Instead, you want to handle the networking layer in some more abstract object such as a Service
of class methods. This is just a simple example, but I think this will really get you heading in a much better architectural direction.
import Alamofire
struct User {
let name: String
let companyName: String
}
class UserService {
typealias UserCompletionHandler = (User?, NSError?) -> Void
class func getUser(completionHandler: UserCompletionHandler) {
let loginRequest = Alamofire.request(.GET, "login/url")
loginRequest.responseJSON { request, response, json, error in
if let error = error {
completionHandler(nil, error)
} else {
println("Login Succeeded!")
let userRequest = Alamofire.request(.GET, "user/url")
userRequest.responseJSON { request, response, json, error in
if let error = error {
completionHandler(nil, error)
} else {
let jsonDictionary = json as [String: AnyObject]
let user = User(
name: jsonDictionary["name"]! as String,
companyName: jsonDictionary["companyName"]! as String
)
completionHandler(user, nil)
}
}
}
}
}
}
UserService.getUser { user, error in
if let user = user {
// do something awesome with my new user
println(user)
} else {
// figure out how to handle the error
println(error)
}
}
Since both the login and user requests are asynchronous, you cannot start using the User object until both requests are completed and you have a valid User object. Closures are a great way to capture logic to run after the completion of asynchronous tasks. Here are a couple other threads on Alamofire and async networking that may also help you out.
Hopefully this sheds some light.