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

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.

这主要是关于感知,但我发现更容易形象化,例如,您可以在一个控制器上开始一个动作并在另一个控制器上做出反应,因为调用花了这么长时间并且您没有阻止应用程序中的导航.