如何从视图控制器中触发异步请求

时间:2015-09-07 23:03:06

标签: swift ios8 sails.js alamofire swifty-json

我正在构建一个iOS应用程序,我刚刚完成了我的登录/注册部分(请求sails.js休息Api) 目前我有2个具有重复代码的视图控制器,因为我在每个类的注册/登录按钮事件监听器上发出其余的调用,并且有很多类似的代码我可以重构。

我想要做的是创建一个名为ApiManager的单例,它将包含我需要的所有调用。 (还有未来的)

问题是,对于异步调用,我无法创建一个函数func login(用户名,密码),它将返回数据,以便我可以存储它们并准备好。

正确实现这一目标的简单/正确方法是什么?这意味着调用ApiManager.myFunction并在任何需要的地方使用结果(填充数据的tableview,启动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

            }
        }

    }

2 个答案:

答案 0 :(得分:2)

我的几乎所有应用程序都以Server类结束,这是唯一知道如何与服务器通信的类。它进行调用,将结果解析为Swift结构并返回它。我的大多数服务器返回json所以我使用SwiftyJSON,但你可以做任何你想做的事。

关键是,因为这是唯一了解服务器通信的类,如果我需要更改用于进行通信的库(AFNetworking 1 vs 2 vs Parse,vs之等),这是我唯一的类需要触摸。

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)")
    }
}

如果所有后续调用都需要用户名/密码,则服务器对象将保留它们的副本。如果登录返回令牌,则服务器会保留该令牌的副本。 QED。

答案 1 :(得分:0)

我通常在我的视图控制器共享的基类中使用实用程序函数,并使用NSNotificationCenter对请求的结果作出反应。它也可以通过授权(协议和代表。

)轻松实现

这主要是关于感知,但我发现你可以更容易想象,例如,你可以在一个控制器上启动一个动作并对另一个控制器作出反应,因为这个调用需要很长时间而且你没有阻止你应用中的导航。 / p>