I have an iOS
application that sync
data from a JSON
restful web service
. This method is called from an external class (not UI controller
). This class has a sync method and It sends and retrieves data without any problem. My problem is how do I pause the UI till I get my result.
The following would provide the idea about the code.
UIController Class
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.
Any kind of help is appreciated. Thanks
You can give the Sync class a completion handler closure.
In your UIViewController
:
S.completion = {
information in
UIElement.updateWith(information)
}
and of course you'll need to add a member to your Syncronization
class:
var completion:((information:String)->())!
and you can call completion("here's some info!")
from inside parseJSON()
or URLSession()
of the Syncronization
class
this might help you 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)
One way of doing that is to include a closure as a parameter to your Sync
function.
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.
We then add a function to be called when done, as a parameter to the Sync
function:
func Sync(C : Customer, callback: (SynchronizationResult) -> Void)
This method will be called with a SynchronizationResult
as a parameter and returns void.
We store that callback in functionToExecuteWhenDone
for later usage.
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)
And in your ViewController you'd do something along the lines of
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")
})
})
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.