问题
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?
回答1:
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.
- Handling Multiple Network Calls
- Returning a Value with Alamofire
Hopefully this sheds some light.
来源:https://stackoverflow.com/questions/28972847/alamofire-nonblocking-connection