在我的应用程序中,我有这个类从我的服务器获取数据:
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
继续旋转。
我想停止活动指示器添加一个子视图,而不是显示没有报价。任何建议将不胜感激。
我尝试过:
if offers.isEmpty{ MBProgressHUD.hideAllHUDsForView(self.view, animated: true) }
还有
if offers == 0 { MBProgressHUD.hideAllHUDsForView(self.view, animated: true) }
但它不起作用
发生这种情况是因为您在主队列中设置了 HUD,但试图从另一个队列中删除。所有与 UI 相关的更改都应在
main_queue()
中完成
尝试使用此代码
dispatch_async(dispatch_get_main_queue(), {
// your code to modify HUD here
});
我建议对代码进行小的重新设计。我对你原来的代码做了一些修改。这是 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上进行了测试,并且与一些测试存根框架配合得很好)。
如果 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]())
}
}
loadOffers
中的每条路径都需要调用完成闭包。 如果您有 if let
陈述,则需要考虑 else
情况。 如果可选项为零,您仍然需要调用完成。 在这种情况下,您可以传递一个空数组,或者您可以向完成块添加一个错误参数,以便视图控制器了解有关为什么它没有返回任何内容的更多信息。