服务器不返回数据时如何停止MBProgressHUD并添加子视图

问题描述 投票:0回答:4

在我的应用程序中,我有这个类从我的服务器获取数据:

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()       
   }
 }

然后在我的视图控制器中加载模型:

    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()
    
    }
 }

一切正常,除了当 JSON 字典为空时,这意味着没有报价

MBProgressHUD
继续旋转。enter image description here

我想停止活动指示器添加一个子视图,而不是显示没有报价。任何建议将不胜感激。

我尝试过:

if offers.isEmpty{ MBProgressHUD.hideAllHUDsForView(self.view, animated: true) }

还有

if offers == 0 { MBProgressHUD.hideAllHUDsForView(self.view, animated: true) }

但它不起作用

ios json swift
4个回答
3
投票

发生这种情况是因为您在主队列中设置了 HUD,但试图从另一个队列中删除。所有与 UI 相关的更改都应在

main_queue()

中完成

尝试使用此代码

dispatch_async(dispatch_get_main_queue(), { 

  // your code to modify HUD here

});

2
投票

我建议对代码进行小的重新设计。我对你原来的代码做了一些修改。这是 API 类:

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()
}

}

更改添加了完成处理程序的调用,即使在网络通信错误和 JSON 解析失败的情况下也是如此。

VC对应的实现如下:

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

}

从我的角度来看,使用闭包更好,但这取决于你的实现。您可以使用方法而不是闭包来使用您的实现,并且只需在实例级别定义 hud 变量。

我希望它可以帮助您解决您的问题(我已经在模拟器和iPhone上进行了测试,并且与一些测试存根框架配合得很好)。


1
投票

如果 myOffers = nil 无法完成(offers)。所以HUD无法停止。你可以试试这个:

 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)

                         }         
                       }                                
                    }
                }
            } else {
         dispatch_async(dispatch_get_global_queue(priority, 0 )){
                                                                               dispatch_async(dispatch_get_main_queue()){

            completion([Offers]())

                         }     
       }

1
投票

loadOffers
中的每条路径都需要调用完成闭包。 如果您有
if let
陈述,则需要考虑
else
情况。 如果可选项为零,您仍然需要调用完成。 在这种情况下,您可以传递一个空数组,或者您可以向完成块添加一个错误参数,以便视图控制器了解有关为什么它没有返回任何内容的更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.