Я разрабатываю приложение для чата, и я настроил следующий механизм для загрузки пользователями сообщений. В принципе, я выталкиваю сообщения в очередь и загружаю их один за другим. Когда очередь пуста, я вызываю finishedUploading
, которая запускается каждую секунду и повторяет задачу, если в очереди есть что-то.Загрузка данных с использованием NSURLSession и очереди
var uploadQueue:[UploadMessage]?
let session = NSURLSession.sharedSession()
let lockQueue = dispatch_queue_create("com.dsdevelop.lockQueue", nil)
// RETURNS AMOUNT OF ITEMS STILL IN QUEUE
func getRemainingActiveUploads() -> Int {
return (self.uploadQueue != nil) ? self.uploadQueue!.count : 0
}
//REMOVES MESSAGE FROM QUEUE ONCE UPLOADED
func removeMessageFromUploadQueue(messageToBeRemoved : UploadMessage) {
if (uploadQueue != nil) {
dispatch_sync(lockQueue) {
self.uploadQueue = self.uploadQueue?.filter({$0.date!.compare(messageToBeRemoved.date!) == NSComparisonResult.OrderedSame})
}
}
}
var uploadTimer : NSTimer?
// CALLED ONLY WHEN UPLOADQUEUE IS EMPTY, RERUNS THE UPLOAD FUNCTION AFTER 1 SECOND
func finishedUploading() {
uploadTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(uploadAllLinks), userInfo: nil, repeats: false)
if (needToRefetch) {
needToRefetch = false
newMessageReceived()
}
}
func uploadAllLinks()
{
uploadTimer?.invalidate()
uploadTimer = nil
// suspending queue so they don't all finish before we can show it
session.delegateQueue.suspended = true
session.delegateQueue.maxConcurrentOperationCount = 1
let myUrl = NSURL(string: "http://****")
// create tasks
if (uploadQueue != nil) {
if (uploadQueue?.count > 0) {
for message in uploadQueue!
{
let request = NSMutableURLRequest(URL:myUrl!)
request.HTTPMethod = "POST"
request.timeoutInterval = 10
request.HTTPShouldHandleCookies=false
var postString = "sender=" + message.sender!
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let dltask = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) in
if data != nil
{
do {
let jsonArray = try NSJSONSerialization.JSONObjectWithData(data_fixed!, options:[])
dispatch_async(dispatch_get_main_queue(), {
if let errorToken = jsonArray["error"] as! Bool? {
if !errorToken {
self.uploadQueue = self.uploadQueue!.filter({$0.date!.compare(message.date!) != NSComparisonResult.OrderedSame})
let remaining = self.getRemainingActiveUploads()
print("Downloaded. Remaining: \(remaining)")
if (remaining == 0) {
self.finishedUploading()
}
}
else {
let remaining = self.getRemainingActiveUploads()
print("Downloaded. Remaining: \(remaining)")
if (remaining == 0) {
self.finishedUploading()
}
}
}
else {
let remaining = self.getRemainingActiveUploads()
print("Downloaded. Remaining: \(remaining)")
if (remaining == 0) {
self.finishedUploading()
}
}
})
}
catch {
print("Error: \(error)")
}
}
})
print("Queuing task \(dltask)")
dltask.resume()
}
session.delegateQueue.suspended = false
}
else {
finishedUploading()
}
// resuming queue so all tasks run
}
}
Теперь это прекрасно работает в следующих двух случаях:
- Очередь пуста ->
finishedUploading
вызывается иuploadAllLinks
запускается каждый второй для проверки элементов вuploadQueue
- очередь имеет один элемент -> один предмет отправлен,
remaining == 0
следовательноfinishedUploading
называется
Однако, когда бы то ни было очередь имеет более одного элемента, первый загружается, if remaining == 0
терпит неудачу, а затем ничего не происходит. Я не понимаю, почему цикл for не запускается для остальных элементов очереди в этот момент.
Как и внутри цикла for, переменная запроса не получает повторной инициализации для каждого элемента в очереди; поэтому десятисекундный интервал применим только к одному элементу в очереди? – Alk
Это так, но каждый элемент имеет десятисекундный тайм-аут, который начинается через несколько микросекунд после предыдущего. Цикл for просто создает задачи сразу после следующего и запускает их, потому что вы не дожидаетесь завершения каждой задачи до начала следующей задачи. – dgatwood
Возможно, что я ошибаюсь в том, что интервал тайм-аута является причиной сбоя, но в любом случае это определенно вызовет довольно последовательные сбои в сотовой сети, поэтому вы не должны этого делать. – dgatwood