(Swift) 在 for 循环中使用带有 NSURLSession 的信号量
(Swift) Using semaphore with a NSURLSession in a for loop
我目前正在尝试从 for 循环中的多个 GET 请求下载数据,然后将其添加到 table 视图。
我成功获取了数据,但我遇到的问题是主线程在从请求下载所有数据之前保持 运行ning,因此它没有加载到 table 视图中。
我正在尝试使用信号量尝试 运行 它一次一个线程,但它似乎没有用。
这是代码:
for item in array{
let http = item["http"] as! String
let URL = NSURL(string: http)
let Request = NSMutableURLRequest(url: URL! as URL)
Request.setValue(self.headerVal, forHTTPHeaderField: "Authorization")
Request.httpMethod = "GET"
let UrlSession = URLSession.shared
let Info = UrlSession.dataTask(with: Request as URLRequest) { (data, response, error) -> Void in
if error != nil{
print(error!)
return;
}
else{
do{
let ResponseData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
guard let results = ResponseData["data"] as? [Any] else {
print("Couldnt get response from \(http)")
return
}
let Result = results[0] as! [String:Any]
self.result.append(Result)
}
catch{
print(error)
}
}
}
Info.resume()
}
print("finished")
self.tableView.reloadData()
如何才能在请求的所有数据下载完成后刷新我的table视图?
我认为最佳解决方案是使用Operation
所以使用这个Operation子类,请调整headerVal类型,我不知道类型
import UIKit
class GetAllData: Operation {
//1
var headerVal : String = "" //I don't know the type of headerVal
var arrayOfDicts : [[String:Any]] = [[:]]
var allDataResult : [[String:Any]] = []
var finishedClosure : (([[String:Any]],Error?)->Void)?
let sema = DispatchSemaphore(value: 0)
var error : Error?
//2
//I don't know the type of headerVal
init(headerVal:String,arrayOfDicts:[[String:Any]]) {
super.init()
self.arrayOfDicts = arrayOfDicts
self.headerVal = headerVal
}
override func cancel() {
self.sema.signal()
}
override func main() {
self.geAllData()
}
func geAllData()
{
//4
if self.isCancelled {
return
}
for item in self.arrayOfDicts{
let http = item["http"] as! String
let URL = NSURL(string: http)
let Request = NSMutableURLRequest(url: URL! as URL)
Request.setValue(self.headerVal, forHTTPHeaderField: "Authorization")
Request.httpMethod = "GET"
let UrlSession = URLSession.shared
let Info = UrlSession.dataTask(with: Request as URLRequest) { (data, response, error) -> Void in
if error != nil{
print(error!)
}
else{
do{
let ResponseData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
guard let results = ResponseData["data"] as? [Any] else {
print("Couldnt get response from \(http)")
return
}
let Result = results[0] as! [String:Any]
self.allDataResult.append(Result)
}
catch{
print(error)
self.sema.signal()
}
}
self.sema.signal()
}
Info.resume()
_ = self.sema.wait(timeout: DispatchTime.distantFuture)
}
print("finished")
if(self.finishedClosure != nil)
{
DispatchQueue.main.async {
self.finishedClosure!(self.allDataResult, nil)
}
}
//7
if self.isCancelled {
return
}
}
}
使用它
self.getAllDataOperation = GetAllData(headerVal: "Your headerVal Here", arrayOfDicts: yourArrayItems)
self.getAllDataOperation!.finishedClosure = { [weak self] (results,error) in
self?.results = results
self?.tableView.reloadData()
}
let OperationQ = OperationQueue()
OperationQ.addOperation(self.getAllDataOperation!)
希望对您有所帮助,如果能解决您的问题,请告诉我
信号量是一种方式,但 DispatchGroup
可能是更好的方式。
let downloadGroup = DispatchGroup()
for item in array{
...
downloadGroup.enter()
let Info = UrlSession.dataTask(with: Request as URLRequest) { (data, response, error) -> Void in
...
downloadGroup.leave()
}
}
downloadGroup.notify(queue: DispatchQueue.main) { // 2
//callback
}
我目前正在尝试从 for 循环中的多个 GET 请求下载数据,然后将其添加到 table 视图。 我成功获取了数据,但我遇到的问题是主线程在从请求下载所有数据之前保持 运行ning,因此它没有加载到 table 视图中。 我正在尝试使用信号量尝试 运行 它一次一个线程,但它似乎没有用。 这是代码:
for item in array{
let http = item["http"] as! String
let URL = NSURL(string: http)
let Request = NSMutableURLRequest(url: URL! as URL)
Request.setValue(self.headerVal, forHTTPHeaderField: "Authorization")
Request.httpMethod = "GET"
let UrlSession = URLSession.shared
let Info = UrlSession.dataTask(with: Request as URLRequest) { (data, response, error) -> Void in
if error != nil{
print(error!)
return;
}
else{
do{
let ResponseData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
guard let results = ResponseData["data"] as? [Any] else {
print("Couldnt get response from \(http)")
return
}
let Result = results[0] as! [String:Any]
self.result.append(Result)
}
catch{
print(error)
}
}
}
Info.resume()
}
print("finished")
self.tableView.reloadData()
如何才能在请求的所有数据下载完成后刷新我的table视图?
我认为最佳解决方案是使用Operation
所以使用这个Operation子类,请调整headerVal类型,我不知道类型
import UIKit
class GetAllData: Operation {
//1
var headerVal : String = "" //I don't know the type of headerVal
var arrayOfDicts : [[String:Any]] = [[:]]
var allDataResult : [[String:Any]] = []
var finishedClosure : (([[String:Any]],Error?)->Void)?
let sema = DispatchSemaphore(value: 0)
var error : Error?
//2
//I don't know the type of headerVal
init(headerVal:String,arrayOfDicts:[[String:Any]]) {
super.init()
self.arrayOfDicts = arrayOfDicts
self.headerVal = headerVal
}
override func cancel() {
self.sema.signal()
}
override func main() {
self.geAllData()
}
func geAllData()
{
//4
if self.isCancelled {
return
}
for item in self.arrayOfDicts{
let http = item["http"] as! String
let URL = NSURL(string: http)
let Request = NSMutableURLRequest(url: URL! as URL)
Request.setValue(self.headerVal, forHTTPHeaderField: "Authorization")
Request.httpMethod = "GET"
let UrlSession = URLSession.shared
let Info = UrlSession.dataTask(with: Request as URLRequest) { (data, response, error) -> Void in
if error != nil{
print(error!)
}
else{
do{
let ResponseData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
guard let results = ResponseData["data"] as? [Any] else {
print("Couldnt get response from \(http)")
return
}
let Result = results[0] as! [String:Any]
self.allDataResult.append(Result)
}
catch{
print(error)
self.sema.signal()
}
}
self.sema.signal()
}
Info.resume()
_ = self.sema.wait(timeout: DispatchTime.distantFuture)
}
print("finished")
if(self.finishedClosure != nil)
{
DispatchQueue.main.async {
self.finishedClosure!(self.allDataResult, nil)
}
}
//7
if self.isCancelled {
return
}
}
}
使用它
self.getAllDataOperation = GetAllData(headerVal: "Your headerVal Here", arrayOfDicts: yourArrayItems)
self.getAllDataOperation!.finishedClosure = { [weak self] (results,error) in
self?.results = results
self?.tableView.reloadData()
}
let OperationQ = OperationQueue()
OperationQ.addOperation(self.getAllDataOperation!)
希望对您有所帮助,如果能解决您的问题,请告诉我
信号量是一种方式,但 DispatchGroup
可能是更好的方式。
let downloadGroup = DispatchGroup()
for item in array{
...
downloadGroup.enter()
let Info = UrlSession.dataTask(with: Request as URLRequest) { (data, response, error) -> Void in
...
downloadGroup.leave()
}
}
downloadGroup.notify(queue: DispatchQueue.main) { // 2
//callback
}