如何从视图控制器中触发异步请求
How can I trigger async requests out of view controller
我正在构建一个 iOS 应用程序,我刚刚完成我的 login/register 部分(请求 sails.js 休息 Api)
目前我有 2 个带有重复代码的视图控制器,因为我在每个 class 的 register/login 按钮事件侦听器上发出其余调用,并且有很多类似的代码我可以重构。
我想做的是创建一个名为 ApiManager 的单例,它将包含我需要的所有调用。 (以及未来的)
问题是,对于异步调用,我无法创建一个函数 func login(username,password) 来 return 数据,这样我就可以存储它们并为segue做准备。
simple/proper 正确实现该目标的方法是什么?这意味着调用 ApiManager.myFunction 并在任何需要的地方使用结果(填充数据的表视图,启动 segue 以登录或成功注册)并使此功能可在另一个视图控制器中重用,即使它用于其他用途。我正在使用 swift.
编辑:以下是我的做法,希望对您有所帮助
执行剩余调用的函数:
func login(#username: String, password: String, resultCallback: (finalresult: UserModel!,finalerror:String!) -> Void) {
Alamofire.request(.POST, AppConfiguration.ApiConfiguration.apiDomain+"/login", parameters: ["username": username,"password": password], encoding: .JSON)
.responseJSON { request, response, data, error in
if let anError = error
{
resultCallback(finalresult: nil,finalerror:anError.localizedDescription)
}else if(response!.statusCode == 200){
var user:UserModel = self.unserializeAuth(data!)//just processing the json using SwiftyJSON to get a easy to use object.
resultCallback(finalresult: user,finalerror:nil)
}else{
resultCallback(finalresult: nil,finalerror:"Username/Password incorrect!")
}
}.responseString{ (request, response, stringResponse, error) in
// print response as string for debugging, testing, etc.
println(stringResponse)
}
}
这就是我从 ViewController 中调用此函数的方式:
@IBAction func onLoginTapped(sender: AnyObject) {//When my user tap the login button
let username = loginInput.text;//taking the content of inputs
let password = passwordInput.text;
ApiManager.sharedInstance.login(username:username,password:password){
[unowned self] finalresult,finalerror in
if(finalresult !== nil){//if result is not null login is successful and we can now store the user in the singleton
ApiManager.sharedInstance.current_user=finalresult
self.performSegueWithIdentifier("showAfterLogin", sender: nil)//enter the actual app and leave the login process
}else{
self.displayAlert("Error!", message: finalerror)//it is basically launching a popup to the user telling him why it didnt work
}
}
}
几乎我所有的应用程序都以 Server
class 结束,这是唯一知道如何与服务器通信的应用程序。它进行调用,将结果解析为 Swift 结构并 returns 它。我的大部分服务器 return json 所以我使用 SwiftyJSON,但你可以做任何你想做的事情。
关键是,因为这是唯一了解服务器通信的 class,如果我需要更改用于进行通信的库(AFNetworking 1 vs 2 vs Parse,vs 其他)这是我唯一需要触摸的 class。
class Server {
static let instance = Server()
func loginWithUsername(username: String, password: String, resultCallback: (result: Either<User, NSError>) -> Void) {
// if login is successful call
resultCallback(result: .Left(self.user!))
// otherwise call
resultCallback(result: .Right(error))
}
}
使用示例:
let server = Server.instance
SVProgressHUD.showWithStatus("Loggin In...")
server.loginWithUsername(username, password: password) { [unowned self] result in
SVProgressHUD.dismiss()
switch result {
case .Left(let user):
self.presentUserType(user.userType)
case .Right(let error):
self.warnUserWithMessage("An error occured. \(error.localizedDescription)")
}
}
如果所有后续调用都需要 username/password,则服务器对象将维护它们的副本。如果登录 return 是一个令牌,那么服务器会保留一份它的副本。
QED.
我通常在我的视图控制器共享的基础 class 中有实用函数,并使用 NSNotificationCenter 对请求的结果做出反应。也可以很容易地通过委托来实现(protocol & delegate.
这主要是关于感知,但我发现更容易形象化,例如,您可以在一个控制器上开始一个动作并在另一个控制器上做出反应,因为调用花了这么长时间并且您没有阻止应用程序中的导航.
我正在构建一个 iOS 应用程序,我刚刚完成我的 login/register 部分(请求 sails.js 休息 Api) 目前我有 2 个带有重复代码的视图控制器,因为我在每个 class 的 register/login 按钮事件侦听器上发出其余调用,并且有很多类似的代码我可以重构。
我想做的是创建一个名为 ApiManager 的单例,它将包含我需要的所有调用。 (以及未来的)
问题是,对于异步调用,我无法创建一个函数 func login(username,password) 来 return 数据,这样我就可以存储它们并为segue做准备。
simple/proper 正确实现该目标的方法是什么?这意味着调用 ApiManager.myFunction 并在任何需要的地方使用结果(填充数据的表视图,启动 segue 以登录或成功注册)并使此功能可在另一个视图控制器中重用,即使它用于其他用途。我正在使用 swift.
编辑:以下是我的做法,希望对您有所帮助
执行剩余调用的函数:
func login(#username: String, password: String, resultCallback: (finalresult: UserModel!,finalerror:String!) -> Void) {
Alamofire.request(.POST, AppConfiguration.ApiConfiguration.apiDomain+"/login", parameters: ["username": username,"password": password], encoding: .JSON)
.responseJSON { request, response, data, error in
if let anError = error
{
resultCallback(finalresult: nil,finalerror:anError.localizedDescription)
}else if(response!.statusCode == 200){
var user:UserModel = self.unserializeAuth(data!)//just processing the json using SwiftyJSON to get a easy to use object.
resultCallback(finalresult: user,finalerror:nil)
}else{
resultCallback(finalresult: nil,finalerror:"Username/Password incorrect!")
}
}.responseString{ (request, response, stringResponse, error) in
// print response as string for debugging, testing, etc.
println(stringResponse)
}
}
这就是我从 ViewController 中调用此函数的方式:
@IBAction func onLoginTapped(sender: AnyObject) {//When my user tap the login button
let username = loginInput.text;//taking the content of inputs
let password = passwordInput.text;
ApiManager.sharedInstance.login(username:username,password:password){
[unowned self] finalresult,finalerror in
if(finalresult !== nil){//if result is not null login is successful and we can now store the user in the singleton
ApiManager.sharedInstance.current_user=finalresult
self.performSegueWithIdentifier("showAfterLogin", sender: nil)//enter the actual app and leave the login process
}else{
self.displayAlert("Error!", message: finalerror)//it is basically launching a popup to the user telling him why it didnt work
}
}
}
几乎我所有的应用程序都以 Server
class 结束,这是唯一知道如何与服务器通信的应用程序。它进行调用,将结果解析为 Swift 结构并 returns 它。我的大部分服务器 return json 所以我使用 SwiftyJSON,但你可以做任何你想做的事情。
关键是,因为这是唯一了解服务器通信的 class,如果我需要更改用于进行通信的库(AFNetworking 1 vs 2 vs Parse,vs 其他)这是我唯一需要触摸的 class。
class Server {
static let instance = Server()
func loginWithUsername(username: String, password: String, resultCallback: (result: Either<User, NSError>) -> Void) {
// if login is successful call
resultCallback(result: .Left(self.user!))
// otherwise call
resultCallback(result: .Right(error))
}
}
使用示例:
let server = Server.instance
SVProgressHUD.showWithStatus("Loggin In...")
server.loginWithUsername(username, password: password) { [unowned self] result in
SVProgressHUD.dismiss()
switch result {
case .Left(let user):
self.presentUserType(user.userType)
case .Right(let error):
self.warnUserWithMessage("An error occured. \(error.localizedDescription)")
}
}
如果所有后续调用都需要 username/password,则服务器对象将维护它们的副本。如果登录 return 是一个令牌,那么服务器会保留一份它的副本。 QED.
我通常在我的视图控制器共享的基础 class 中有实用函数,并使用 NSNotificationCenter 对请求的结果做出反应。也可以很容易地通过委托来实现(protocol & delegate.
这主要是关于感知,但我发现更容易形象化,例如,您可以在一个控制器上开始一个动作并在另一个控制器上做出反应,因为调用花了这么长时间并且您没有阻止应用程序中的导航.