如何使用swift从异步URL请求中获取结果?

时间:2015-05-24 09:06:51

标签: swift

我正在尝试在应用中实现登录功能。我有一个带有用户名和密码的网址,验证它们是否正确并返回true或false。如果为true,则应加载新的视图控制器。

1)如何从viewController中的异步url调用中获取结果?来自服务器的响应是正确的,并且json传递是正确的。但是我不确定如何在viewController中获得结果。我已经阅读了有关堆栈溢出的其他问题,一些人提到了委托和completionHandler的使用。我查找了如何使用委托,但我不太确定如何在这种情况下使用它。

所以这是我的代码。 在一个课程中我有这个功能。我通过单例访问此功能。我在viewController的shouldPerformSegueWithIdentifier方法中调用它(如下所示)。

func loginRequest() -> Bool {


    let urlPath: String = "http:**************.mybluemix.net/login/login.php?username=Tony&password=pass"
    var url: NSURL = NSURL(string: urlPath)!
    var request1: NSURLRequest = NSURLRequest(URL: url)
    let queue:NSOperationQueue = NSOperationQueue()
    var loginRequest:Bool = false
    NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
        var err: NSError
        var jsonResult: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: nil)
        println("AsSynchronous\(jsonResult)")

        if let jsonDictionary = jsonResult as? NSDictionary {
            if let success = jsonDictionary["Success"] as? NSString {
                if success == "true" {
                    // User has permission to login.
                    loginRequest = true
                    println("login should be true: \(loginRequest)")

                }else{
                    // User does not have permission to login.
                    loginRequest = false
                    println("login should be false: \(loginRequest)")
                }
            }

        }

    })
}

此功能位于视图控制器中。

    override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool {
    if identifier == "SubmitLogin" {
        // Username empty.
        if(username.text.isEmpty){
            let alert = UIAlertView()
            alert.title = "no Text"
            alert.message = "No username or password"
            alert.addButtonWithTitle("OK")
            alert.show()
            return false
        }else{
            // Send login credentials to server.
            var login = (Model.sharedInstance.loginRequest())
            // loginRequest returns ture if credentials are correct.
            if (Model.sharedInstance.loginRequest()){
                // Start the next view controller.
                return true
            }else{
                // Login failed
                let alert = UIAlertView()
                alert.title = "Failed Login"
                alert.message = "The username or password was wrong. Please try again"
                alert.addButtonWithTitle("OK")
                alert.show()
                return false
            }

        }
    }
}

那么如何使用NSURLConnection.sendAsynchronousRequest的委托来检索viewcontroller中的结果并使用结果来确定是否应该将用户登录?

******编辑澄清******

我有一个名为BluemixDAO的类,它看起来像:

类BluemixDAO {

init(){
}

// The login function that I posted above
func loginRequest() -> Bool {
}
}

下一个类是Model,用于调用BluemixDAO loginRequest函数。

class Model {
private let bluemix:BluemixDAO
private struct Static
{
static private var instance:Model?
}
class var sharedInstance: Model
{
if !(Static.instance != nil)
{
return Static.instance!
}
}

private init(){
bluemix = BluemixDAO()
}

// I call this function in my view controller using Model.sharedInstance.loginRequest()
func loginRequest() -> Bool 
{
// This calls the function in the BluemixDAO class
return bluemix.loginRequest()
}
}

最后一个类是viewController。它只有上面的函数“shouldPerformSegueWithIdentifier”

class viewController: UIViewController {

//This function is detailed at the top of the post.
    override func shouldPerformSegueWithIdentifier(identifier: String?, sender:AnyObject?) ->  Bool {
     // I call the loginRequest() function in here.
}
}

我写得太多了。这应该是所有相关的代码。 干杯

1 个答案:

答案 0 :(得分:3)

似乎你的异步块和你的函数在同一个类中,所以你唯一需要做的就是在主线程中调用你的函数,在async块中添加这个代码来执行此操作:

dispatch_async(dispatch_get_main_queue())
{
        //call your function
}

如果要将结果发送到其他班级,您也可以通过协议发送通知或发送结果。

我个人停止使用UIAlertView进行登录,因为您无法更新它以显示登录失败的详细信息或用于在处理数据时显示旋转轮,我更喜欢创建一个新的UIViewController并将其弹出到屏幕中完成所有登录过程并解散。

使用协议

要将值从一个类传递到另一个类,您需要实现协议。在执行登录的类中声明一个这样的协议:

protocol LoginDelegate
{
    func loginResult(result: Bool)
}

在同一控件中将可选委托声明为全局:

var loginDelegate:LoginDelegate? = nil

现在在打开它之前测试这个委托是否存在,以及它是否在协议中调用函数声明:

if let loginDel = self.loginDelegate{
    loginDel.loginResult(userResult)
}

这将帮助我们将值传递给请求它的类,在这个类中,您需要扩展这个新协议:

extension MainViewController: LoginDelegate{ }

在viewDidLoad中,将此视图控制器声明为登录类

中的委托
login.loginDelegate = self

现在要符合协议,我们只需要实现将由详细视图控制器使用布尔值调用的函数:

extension LoginViewController: LoginDelegate
{
    func loginResult(result: Bool)
    {
       //Save the result value to be used by the MainViewController
    }
}

我知道这不是一个非常简单的过程,在使用它几次后会更容易使用和理解,这总是一个好主意在这里的文档中阅读更多

使用通知

要使用通知添加此代码,以便在检查用户完成的过程中发送新通知,该字典包含您希望在通知中传递的数据,在这种情况下是登录过程的结果:

dispatch_async(dispatch_get_main_queue())
{
    let dic = ["result":result]
    NSNotificationCenter.defaultCenter().postNotificationName("loginResult", object: nil, userInfo: dic)     
}

使用以下代码注册负责处理邮件的班级:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "login:", name:"loginResult", object: nil)

收到通知后,选择器将调用下面的函数,将通知转换为在字典中添加的键:

func login(notification: NSNotification){
    if let result: AnyObject = notification.userInfo?["result"]
    {
        //do your logic
    }
}

完成课程后请不要忘记取消注册通知,否则您将发生内存泄漏

NSNotificationCenter.defaultCenter().removeObserver(self)