问题
I am making a webservice call to get a list of data. After I have all of that data I would like to make a web call for every item on that list. Here is the code I have this far:
let zipcde:String = self.zipCode
let username:String = "tr1gger"
//webservice call
var listZip = [String]()
let wsUrl: NSURL = NSURL(string: "http://api.url.org/findNearbyTheseCodesJSON?postalcode=" + zipcde + "&maxRows=100&country=US&radius=25&username=" + username)!
let task = NSURLSession.sharedSession().dataTaskWithURL(wsUrl, completionHandler: { (data, response, error) -> Void in
//will happen when task is complete
if let urlContent = data {
let jsonObject = JSON(data: urlContent)
if let jsonDict:JSON = jsonObject["postalCodes"]{
let postalCode = "postalCode"
for var i:Int = 0; i < jsonDict.count; i++ {
print("Property: \"\(jsonDict[i][postalCode])\"")
listZip.append(String(jsonDict[i][postalCode]))
}
self.showLoadingMessage()
self.listOfZips = listZip
self.getStores()
}
}
})
task.resume()
the self.getStores is a function that begins a for loop and calls a webservice for every item on the first list:
func getStores(){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
for areaCode in self.listOfZips{
let url = NSURL(string: "http://myUrl.thisPlace.net/getStores.php?zipcode=" + areaCode + "&ammoType=" + self.aType)!
let task2 = NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data2, response2, error2) -> Void in
if let jsonObject2: NSArray = (try? NSJSONSerialization.JSONObjectWithData(data2!, options: NSJSONReadingOptions.MutableContainers)) as? NSArray{
var storeName = [String]()
var storeAddress = [String]()
var storeId = [String]()
var ammoStId = [String]()
var ammoStock = [String]()
var ammoPrice = [String]()
for obj in jsonObject2{
if let name: String = obj["storeName"] as? String{
storeName.append(name)
storeAddress.append((obj["storeAddress"] as? String)!)
storeId.append((obj["storeId"]as? String)!)
}
else if let id: String = obj["storeId"] as? String{
ammoStId.append(id)
ammoStock.append((obj["ammoStock"] as? String)!)
if let priceTemp: String = obj["ammoPrice"] as? String{
ammoPrice.append(priceTemp)
}
}
}
var storeList = [StoreItem]()
for var index:Int = 0; index < storeId.count; ++index{
let sId = storeId[index]
for var i:Int = 0; i < ammoStId.count; ++i{
let aId = ammoStId[i]
if sId == aId{
//creating object
let storeItem:StoreItem = StoreItem()
storeItem.setAddress(storeAddress[index])
storeItem.setName(storeName[index])
storeItem.setId(Int(storeId[index])!)
storeItem.setAmmoStock(Int(ammoStock[i])!)
storeItem.setAmmoPrice(ammoPrice[i])
storeList.append(storeItem)
}
}
}
self.storeListFinal.appendContentsOf(storeList)
}
self.myAlert.dismissViewControllerAnimated(true, completion: nil)
self.tableView.reloadData()
})
task2.resume()
}
})
As you can see I am populating a table at the end of this call. This code takes about 18-20 seconds to finish. On my android version it takes like 2 seconds. How can I optimize this?
Thanks for any help.
回答1:
Invoke UI update (reload table) in background thread can cause delay. So, you should move the UI update code to main thread:
let task2 = NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data2, response2, error2) -> Void in
....
dispatch_async(dispatch_get_main_queue(), {
self.myAlert.dismissViewControllerAnimated(true, completion: nil)
self.tableView.reloadData()
})
})
This way above can temporary solve your problem, but, it will reload you table many times because you create many tasks in loop. You should think another way to improve this.
回答2:
I am making a webservice call to get a list of data. After I have all of that data I would like to make a web call for every item on that list.
This sort of situation is exactly the subject of the WWDC 2015 video on Advanced NSOperations. By using an NSOperation to encapsulate each your network "tasks", you can create the dependencies you need (the web service call must complete successfully before anything else can happen) and queue up the other "tasks" (the web call for each item) so that they are all performed independently and in good order. You'll find that the logic of expressing this sort of ordered dependency is much easier to express if you use NSOperations in this way. Watch the video, you'll see what I mean.
回答3:
You used shared NSURLSession
and it seems to that session queued what you requested. The secondary queries are not executed in same time, I think this is the reason for slow performance.
You can change max concurrent connection count for each host by below code:
NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.HTTPMaximumConnectionsPerHost = 20;
Above codes may have to be called before any shared NSURLSession
is created. To make it sure, I suggest that you should create a custom NSURLSession that uses explicitly defined configuration.
ps. IMO, changing serve scripts so the sever can provide results with just 1 call is Best Solution if You can.
回答4:
use, dispatch_sync with background thread. You can find solution, in my post, there: Swift Serial Dispatch Block only finish after delegate
来源:https://stackoverflow.com/questions/33178204/how-to-download-and-process-2-sets-of-data-one-after-the-other