简体   繁体   English

NSURLSession,完成块,Swift

[英]NSURLSession, Completion Block, Swift

Im working with NSURLSession. 我正在使用NSURLSession。 I have an array with restaurants and i'm requesting the dishes for every restaurant in the array to the api. 我有一个带有餐厅的数组,我向api中的数组中的每个餐厅索要菜肴。 The dataTask works,i'm just having a real hard time trying to call a method only when the all dataTasks are finished. dataTask工作正常,仅在所有dataTasks完成后才尝试调用方法确实很困难。

 self.findAllDishesOfRestaurants(self.restaurantsNearMe) { (result) -> Void in
        if result.count != 0 {
              self.updateDataSourceAndReloadTableView(result, term: "protein")
        } else {
            print("not ready yet")
        } 
    }

the self.updateDataSourceAndREloadTableView never gets called, regardless of my completion block. 无论我的完成块如何,self.updateDataSourceAndREloadTableView都不会被调用。 Here is my findAllDishesOfRestaurants function 这是我的findAllDishesOfRestaurants函数

func findAllDishesOfRestaurants(restaurants:NSArray, completion:(result: NSArray) -> Void) {
    let allDishesArray:NSMutableArray = NSMutableArray()
    for restaurant in restaurants as! [Resturant] {
        let currentRestaurant:Resturant? = restaurant
        if currentRestaurant == nil {
            print("restaurant is nil")
        } else {
            self.getDishesByRestaurantName(restaurant, completion: { (result) -> Void in
                                            if let dishesArray:NSArray = result {
                                                restaurant.dishes =  dishesArray
                                                print(restaurant.dishes?.count)
                                                allDishesArray.addObjectsFromArray(dishesArray as [AnyObject])
                                                self.allDishes.addObjectsFromArray(dishesArray as [AnyObject])
                                                print(self.allDishes.count)
                                            }
                                            else {
                                                print("not dishes found")
                                        }
                                          // completion(result:allDishesArray)
                                    })
             completion(result:allDishesArray)
        }
    }
}

And here is my the function where i perform the dataTasks. 这是我执行dataTasks的函数。

 func getDishesByRestaurantName(restaurant:Resturant, completion:(result:NSArray) ->Void) {

    var restaurantNameFormatted = String()
    if let name = restaurant.name {
    for charachter in name.characters {
        var newString = String()
        var sameCharacter:Character!
        if charachter == " " {
           newString = "%20"
            restaurantNameFormatted = restaurantNameFormatted + newString
        } else {
            sameCharacter = charachter
            restaurantNameFormatted.append(sameCharacter)
        }
       // print(restaurantNameFormatted)
    }
}
    var urlString:String!
        //not to myself, when using string with format, we need to igone all  the % marks arent ours to replace with a string, otherwise they will be expecting to be replaced by a value
         urlString = String(format:"https://api.nutritionix.com/v1_1/search/%@?results=0%%3A20&cal_min=0&cal_max=50000&fields=*&appId=XXXXXXXXXappKey=XXXXXXXXXXXXXXXXXXXXXXXXXXXX",restaurantNameFormatted)
    let URL = NSURL(string:urlString)
    let restaurantDishesArray = NSMutableArray()
  let session = NSURLSession.sharedSession()
                let dataTask = session.dataTaskWithURL(URL!) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
                do {
                let anyObjectFromResponse:AnyObject = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments)
                    if let asNSDictionary = anyObjectFromResponse as? NSDictionary {
                        let hitsArray = asNSDictionary.valueForKey("hits") as? [AnyObject]
                                                for newDictionary in hitsArray! as! [NSDictionary]{
                                                    let fieldsDictionary = newDictionary.valueForKey("fields") as? NSDictionary
                                                    let newDish = Dish.init(dictionary:fieldsDictionary!, restaurant: restaurant)
                                                    restaurantDishesArray.addObject(newDish)
                        }
                    }
                    completion(result:restaurantDishesArray)
                } catch let error as NSError {
                    print("failed to connec to api")
                    print(error.localizedDescription)
                }
            }
            dataTask.resume()
}

Like i said before, I need to wait until the fun findAllDishesOfRestaurants is done. 就像我之前说过的那样,我需要等到有趣的findAllDishesOfRestaurants完成。 I tried writing my completion blocks but I'm not sure I'm doing it right. 我尝试编写完成块,但不确定执行是否正确。 Any help is greatly appreciated. 任何帮助是极大的赞赏。 Thank 谢谢

The problem is that you are calling the completion method in findAllDishesOfRestaurants before al tasks are complete. 问题是您要在completion任务之前在findAllDishesOfRestaurants中调用completion方法。 In fact, you are calling it once for each restaurant in the list, which is probably not what you want. 实际上,您为列表中的每个餐厅都调用一次,这可能不是您想要的。

My recommendation would be for you to look into NSOperationQueue for two reasons: 我的建议是让您研究NSOperationQueue的原因有两个:

  1. It will let you limit the number of concurrent requests to the server, so your server does not get flooded with requests. 这将使您限制对服务器的并发请求数,因此服务器不会被请求淹没。
  2. It will let you easily control when all operations are complete. 它使您可以轻松控制何时完成所有操作。

However, if you are looking for a quick fix, what you need is to use GCD groups dispatch_group_create , dispatch_group_enter , dispatch_group_leave , and dispatch_group_notify as follows. 但是,如果您正在寻找快速解决方案,则需要使用GCD组dispatch_group_createdispatch_group_enterdispatch_group_leavedispatch_group_notify ,如下所示。

func findAllDishesOfRestaurants(restaurants:NSArray, completion:(result: NSArray) -> Void) {
    let group = dispatch_group_create() // Create GCD group

    let allDishesArray:NSMutableArray = NSMutableArray()
    for restaurant in restaurants as! [Resturant] {
        let currentRestaurant:Resturant? = restaurant
        if currentRestaurant == nil {
            print("restaurant is nil")
        } else {
            dispatch_group_enter(group) // Enter group for this restaurant
            self.getDishesByRestaurantName(restaurant, completion: { (result) -> Void in
                if let dishesArray:NSArray = result {
                    restaurant.dishes =  dishesArray
                    print(restaurant.dishes?.count)
                    allDishesArray.addObjectsFromArray(dishesArray as [AnyObject])
                    // self.allDishes.addObjectsFromArray(dishesArray as [AnyObject])  <-- do not do this
                    // print(self.allDishes.count)
                }
                else {
                    print("not dishes found")
                }
                // completion(result:allDishesArray)  <-- No need for this, remove
                dispatch_group_leave(group) // Leave group, marking this restaurant as complete
            })
            // completion(result:allDishesArray) <-- Do not call here either
        }
    }

    // Wait for all groups to complete
    dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
        completion(result:allDishesArray)
    }
}

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

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