NSURLSession,完成块,Swift
Posted
技术标签:
【中文标题】NSURLSession,完成块,Swift【英文标题】:NSURLSession, Completion Block, Swift 【发布时间】:2015-10-16 03:44:06 【问题描述】:我正在使用 NSURLSession。我有一个包含餐厅的数组,我正在请求数组中每个餐厅的菜肴到 api。 dataTask 有效,我只是在所有 dataTask 都完成后才尝试调用方法。
self.findAllDishesOfRestaurants(self.restaurantsNearMe) (result) -> Void in
if result.count != 0
self.updateDataSourceAndReloadTableView(result, term: "protein")
else
print("not ready yet")
self.updateDataSourceAndREloadTableView 永远不会被调用,无论我的完成块如何。这是我的 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)
这是我执行数据任务的函数。
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()
就像我之前说的,我需要等到有趣的 findAllDishesOfRestaurants 完成。我试着写我的完成块,但我不确定我做得对。任何帮助是极大的赞赏。谢谢
【问题讨论】:
【参考方案1】:问题是您在所有任务完成之前调用findAllDishesOfRestaurants
中的completion
方法。实际上,您为列表中的每家餐厅调用一次,这可能不是您想要的。
我的建议是让您查看NSOperationQueue
,原因有两个:
-
它可以让您限制对服务器的并发请求数,这样您的服务器就不会被请求淹没。
它可以让您轻松控制所有操作何时完成。
但是,如果您正在寻找快速解决方案,您需要使用 GCD 组 dispatch_group_create
、dispatch_group_enter
、dispatch_group_leave
和 dispatch_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)
【讨论】:
是的,我只是将完成部分留在那里,否则它不会被调用,直到为时已晚。您的建议听起来很棒,我什至从未听说过。非常感谢您,我会告诉您进展如何并接受您的回答。 老兄!非常感谢您的建议,“快速修复”工作,但我更关注 NSPertationQueue。以上是关于NSURLSession,完成块,Swift的主要内容,如果未能解决你的问题,请参考以下文章
如何在移动到下一行代码之前完成 NSURLSession 请求
未调用 NSURLSessionDataTask 完成处理程序块