【问题标题】:How to get results from an asynchronous url request using swift?如何使用 swift 从异步 url 请求中获取结果?
【发布时间】:2015-05-24 09:06:50
【问题描述】:

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

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

这是我的代码。 在一个班级中,我有这个功能。我通过单例访问此功能。我在 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 来检索视图控制器中的结果并使用结果来确定我是否应该让用户登录?

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

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

类 BluemixDAO {

init(){
}

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

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

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.
}
}

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

【问题讨论】:

    标签: swift


    【解决方案1】:

    您的异步块和函数似乎在同一个类中,所以您唯一需要做的就是在主线程中调用您的函数,并在异步块中添加此代码:

    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)
    

    【讨论】:

    • 对不起,我不是更清楚,我有三个类。一个是称为 Model 的单例。另一个只是一个名为 BluemixDAO 的类,该类的一个对象是在 Model 中创建的。然后我在另一个类中有视图控制器。我使用 Model.sharedInstance.loginRequest() 来调用 BluemixDAO 类中的 loginRequest() 函数。我将更新问题以使其更清楚。
    • 我明白了,所以我可以使用协议或通知(观察者模式?)来传递数据。如何以及在何处调用 dispatch_async(dispatch_get_main_queue()) 函数。
    • 是的,您将使用其中一种,在您的情况下,我认为协议是一个更好的选择,当我可能在不同的类中多次使用相同的消息时,我通常使用通知。
    • 返回块在后台线程中返回,您需要 dispatch_async 来调用任何更新 UI 的函数
    • 非常感谢。快速淋浴后我会去。我希望这有效
    猜你喜欢
    • 2020-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-05
    • 2013-12-27
    • 1970-01-01
    • 2016-04-01
    • 1970-01-01
    相关资源
    最近更新 更多