In my app I have this class to get data from my server:
class Api{
func loadOffers(completion:(([Offers])-> Void), offer_id: String, offerStatus:String){
let myUrl = NSURL(string: "http://www.myServer.php/api/v1.0/offers.php")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let postString = "offer_id=\(offer_id)&offerStatus=\(dealStatus)&action=show"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{ data, response, error in
if error != nil {
println("error\(error)")
}else{
var err:NSError?
let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil)
if let dict = jsonObject as? [String: AnyObject] {
if let myOffers = dict["offers"] as? [AnyObject] {
var offers = [Offers]()
for offer in myOffers{
let offer = Offers(dictionary: offer as! NSDictionary)
offers.append(offer)
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0 )){
dispatch_async(dispatch_get_main_queue()){
completion(offers)
}
}
}
}
}
}
}
task.resume()
}
}
then in my View Controller I load the model:
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var offers: [Offers]!
func loadModel() {
let loadingNotification = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
loadingNotification.mode = MBProgressHUDMode.Indeterminate
loadingNotification.labelText = "updating your offers..."
offers = [Offers]()
let api = Api()
api.loadOffers(didLoadOffers , offer_id: dealIdent!, offerStatus: "open")
}
func didLoadOffers(offers:[Offers]){
self.offers = offers
self.tableView.reloadData()
MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
self.refreshControl.endRefreshing()
}
override func viewWillAppear(animated: Bool) {
loadModel()
}
}
Everything works except that when the JSON dictionary is empty, meaning that there no offers the MBProgressHUD
keep spinning.
I would like stop the activity indicator adding a subview instead which says that there are no offers. Any Suggestion would be greatly appreciated.
I tried:
if offers.isEmpty{
MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
}
and also
if offers == 0 {
MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
}
but it's not working
Thanks
This is happening because you set the HUD in main queue but are trying to remove from another one. All UI related changes should be done in main_queue()
Try using this code
dispatch_async(dispatch_get_main_queue(), {
// your code to modify HUD here
});
I recommend small redesign of code. I modified your original code a little. Here is API class:
class Api {
func loadOffers(offerID : String, offerStatus : String, completionHandler : ([Offer]?, NSError?) -> Void) {
let myURL = NSURL(string: "http://www.myServer.php/api/v1.0/offers.php")!
var request = NSMutableURLRequest(URL: myURL)
request.HTTPMethod = "POST"
let postString = "offer_id=\(offerID)&offerStatus=\(offerStatus)&action=show"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (result : NSData!, response : NSURLResponse!, error : NSError!) -> Void in
if let existingError = error {
NSLog("error \(existingError.code) - \(existingError.localizedDescription)")
completionHandler(nil, existingError)
} else {
var parseError : NSError?
if let dictionary = NSJSONSerialization.JSONObjectWithData(result, options: .allZeros, error: nil) as? [String : AnyObject] {
if let myOffers = dictionary["offers"] as? [NSDictionary] {
var parsedOffers = [] as [Offer]
for jsonOffer in myOffers {
parsedOffers.append(Offer(dictionary: jsonOffer))
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
completionHandler(parsedOffers, nil)
}
}
} else {
NSLog("JSON parsing failed")
parseError = NSError(domain: "MyApp", code: 1, userInfo : nil)
completionHandler(nil, parseError)
}
}
}).resume()
}
}
Change is added calling of completion handler even in case error with network communication and in case of failure of JSON parsing.
Corresponding implementation of VC follows:
class ViewController: UITableViewController {
private var _offers : [Offer]?
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
loadModel()
}
private func loadModel() {
var hud = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
hud.mode = MBProgressHUDMode.Indeterminate
hud.labelText = "updating your offers"
Api().loadOffers("1", offerStatus: "1") { (offers : [Offer]?, error : NSError?) -> Void in
self._offers = offers
// TODO: Correct handling of error state ;)
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
hud.hide(true)
}
}
}
}
From my point of view is using closure better, but depends on your implementation. You can use your implementation with method instead of closure and just define hud variable on instance level.
I hope it helps you to solve your problem (I've tested on simulator and iPhone and works well with some testing stub framework).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With