简体   繁体   English

如何在iOS中使用异步方法(JSON Restful服务)?

[英]How to use asynchronous methods (JSON Restful services) in iOS?

I have an iOS application that sync data from a JSON restful web service . 我有一个iOS应用程序,可以sync来自JSON restful web service This method is called from an external class (not UI controller ). 从外部类(不是UI controller )调用此方法。 This class has a sync method and It sends and retrieves data without any problem. 这个类有一个sync方法,它可以毫无问题地发送和检索数据。 My problem is how do I pause the UI till I get my result. 我的问题是如何在获得结果之前暂停UI。

The following would provide the idea about the code. 以下将提供有关代码的想法。

UIController Class UIController类

let C : Customer = Customer(UserName: UserName!, Password: Password!)
let S : Syncronization = Syncronization()
S.Sync(C)

Syncronization class 同步类

Class Syncronization : NSObject, NSURLSessionDataDelegate

func Sync(C : Customer){
        var datastr = ""
        datastr = "http://192.168.248.134:8008/MobileWeb.svc/GetFirstTimeSync/" + C.UserName + "/" + C.Password
        let url:NSURL = NSURL(string: datastr)!
        self.buffer = NSMutableData()
        let defaultConfigObject:NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
        let session:NSURLSession = NSURLSession(configuration: defaultConfigObject, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
        let req:NSMutableURLRequest = NSMutableURLRequest(URL: url)
        req.HTTPMethod = "POST"
        session.dataTaskWithURL(url).resume()
    }

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
        print("Recieved with data")
        buffer.appendData(data)
    }

func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
            if error == nil {
                print("Download Successful")
                print("Done with Bytes " + String(buffer.length))
                self.parseJSONA(self.buffer)
            }
            else  {
                print("Error %@",error!.userInfo);
                print("Error description %@", error!.localizedDescription);
                print("Error domain %@", error!.domain);
            }
    }

    func parseJSONA(data:NSMutableData) {
         do {
                let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! Array<AnyObject>
        } catch let error as NSError {
                print("Failed to load: \(error.localizedDescription)")
        }
   }

I have tried dispacther methods, but I believe I do not know how to use that so far cause most of the examples have down the services & data exchange on UI Controllers. 我已经尝试过dispacther方法,但我相信我到目前为止还不知道如何使用它,因为大多数示例都关闭了UI控制器上的服务和数据交换。

Any kind of help is appreciated. 任何形式的帮助表示赞赏。 Thanks 谢谢

You can give the Sync class a completion handler closure. 您可以为Sync类提供完成处理程序闭包。

In your UIViewController : 在你的UIViewController

S.completion = {
 information in
 UIElement.updateWith(information)
}

and of course you'll need to add a member to your Syncronization class: 当然,您需要在Syncronization类中添加一个成员:

var completion:((information:String)->())!

and you can call completion("here's some info!") from inside parseJSON() or URLSession() of the Syncronization class 你可以从Syncronization类的parseJSON()URLSession()内部调用completion("here's some info!")

Here's some reading on closures in Swift 这里有关于Swift闭包的一些解读

this might help you https://thatthinginswift.com/background-threads/ 这可能会帮助你https://thatthinginswift.com/background-threads/

let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {

    // do downloading or sync task here

    dispatch_async(dispatch_get_main_queue()) {

        // update some UI with downloaded data/sync data

    }
}

If I understand you correctly, you want to be able to do something in your UI based on the outcome of your call to S.Sync(C) 如果我理解正确,您希望能够根据您对S.Sync(C)调用结果在您的UI中执行某些操作

One way of doing that is to include a closure as a parameter to your Sync function. 一种方法是将闭包作为Sync函数的参数。

Here's how I would do that (Disclaimer...I haven't checked everything in a compiler, so there might be errors along the way. See how far you get, and if there are problems, just write again :-)): 这是我将如何做到的(免责声明......我没有检查编译器中的所有内容,因此可能会出现错误。看看你得到了多少,如果有问题,只需再写一次:-)):

enum SynchronizationResult {
    case Success(Array<AnyObject>)
    case Failure(NSError)
}

class Syncronization : NSObject, NSURLSessionDataDelegate {

    var functionToExecuteWhenDone: ((SynchronizationResult) -> Void)?

    func Sync(C : Customer, callback: (SynchronizationResult) -> Void){
        functionToExecuteWhenDone = callback
        var datastr = ""
        datastr = "http://192.168.248.134:8008/MobileWeb.svc/GetFirstTimeSync/" + C.UserName + "/" + C.Password
        let url:NSURL = NSURL(string: datastr)!
        self.buffer = NSMutableData()
        let defaultConfigObject:NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
        let session:NSURLSession = NSURLSession(configuration: defaultConfigObject, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
        let req:NSMutableURLRequest = NSMutableURLRequest(URL: url)
        req.HTTPMethod = "POST"

        session.dataTaskWithURL(url).resume()
     }

    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
        print("Recieved with data")
        buffer.appendData(data)
    }

    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
        if error == nil {
            print("Download Successful")
            print("Done with Bytes " + String(buffer.length))
            self.parseJSONA(self.buffer)
        } else  {
            print("Error %@",error!.userInfo);
            print("Error description %@", error!.localizedDescription);
            print("Error domain %@", error!.domain);
            let result = SynchronizationResult.Failure(error!)
            if let functionToExecuteWhenDone = functionToExecuteWhenDone {
                functionToExecuteWhenDone(result)
            }
        }
    }

    func parseJSONA(data:NSMutableData) {
        do {
            let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! Array<AnyObject>
            let result = SynchronizationResult.Success(json)
            if let functionToExecuteWhenDone = functionToExecuteWhenDone {
                functionToExecuteWhenDone(result)
            }
         } catch let error as NSError {
             print("Failed to load: \(error.localizedDescription)")
             let result = SynchronizationResult.Failure(error)
             if let functionToExecuteWhenDone = functionToExecuteWhenDone {
                 functionToExecuteWhenDone(result)
             }
         }
     }
}

So...we introduce an Enum called SynchronizationResult to handle the outcome of fetching data. 所以...我们引入了一个名为SynchronizationResult的Enum来处理获取数据的结果。

We then add a function to be called when done, as a parameter to the Sync function: 然后我们添加一个要在完成时调用的函数,作为Sync函数的参数:

func Sync(C : Customer, callback: (SynchronizationResult) -> Void)

This method will be called with a SynchronizationResult as a parameter and returns void. 将使用SynchronizationResult作为参数调用此方法,并返回void。

We store that callback in functionToExecuteWhenDone for later usage. 我们将该回调存储在functionToExecuteWhenDone供以后使用。

Depending on whether you see any errors along the way or everything is sunshine, we generate different SynchronizationResult values along the way and call your functionToExecuteWhenDone with the current SynchronizationResult when we are ready (when parsing is done or we have failed) 根据您是否看到任何错误或一切都是阳光,我们在此过程中生成不同的SynchronizationResult值,并在我们准备好时(当解析完成或我们失败时)使用当前的SynchronizationResult调用functionToExecuteWhenDone

And in your ViewController you'd do something along the lines of 在你的ViewController中,你可以做一些事情

let C : Customer = Customer(UserName: UserName!, Password: Password!)
let S : Syncronization = Syncronization()
S.Sync(C) { (result) in
    switch result {
        case .Success(let json):
            //Your code to update UI based on json goes here
        case .Failure(let error):
            //Your code to handle error goes here
    }
}

I hope this makes sense and is what you needed. 我希望这是有道理的,也是你需要的。

let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
    print("This is run on the background queue")

   dispatch_async(dispatch_get_main_queue(), { () -> Void in
        print("This is run on the main queue, after the previous code in outer block")
    })
})

Found here 在这里找到

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM