简体   繁体   English

从URL异步下载和上传数据

[英]Downloading & Uploading Data From URL Swift Asynchronously

I have an array of 5 links which contain either jpg or mov files. 我有5个链接数组,其中包含jpgmov文件。 I want to download them into my iOS Swift app. 我想将它们下载到我的iOS Swift应用中。 I use the following code. 我使用以下代码。

var index = 0
while (index < myLinks.count) {
if (myLinks[index].resource_type == "image") {
    let stringURL = "http://www.blablabla" + ".jpg"
    let url = NSURL(string : stringURL)
    getDataFromUrl(url!) { (data, response, error)  in
        guard let data = data where error == nil else { return }
        print(response?.suggestedFilename ?? url!.lastPathComponent ?? "")
        print("Download Finished")
        myLinks[index].image = UIImage(data: data)
    }
}
else if (myLinks[index].resource_type == "video") {
    let stringURL = "http://www.blablabla" + ".mov"
    let url = NSURL(string : stringURL)
    getDataFromUrl(url!) { (data, response, error)  in
        guard let data = data where error == nil else { return }
        print(response?.suggestedFilename ?? url!.lastPathComponent ?? "")
        print("Download Finished")
        dispatch_async(dispatch_get_main_queue(), {
            let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
            let documentsDirectory : NSString = paths[0]
            let appFile = documentsDirectory.stringByAppendingPathComponent(myLinks[index].id! + ".m4v")
            do {
                try data.writeToFile(appFile, options: .AtomicWrite)
                myLinks[index].videoURL =  NSURL(fileURLWithPath: appFile)
            }
            catch _ {
                print("error saving video")
            }
        })
    }
}

index = index + 1
}


 func getDataFromUrl(url: NSURL, completion: ((data: NSData?, response: NSURLResponse?, error: NSError? ) -> Void)) {
    NSURLSession.sharedSession().dataTaskWithURL(url) {
        (data, response, error) in
        completion(data: data, response: response, error: error)
        }.resume()
}

Now the only problem is that, after downloading these resources, I want to display them to the user in a form of slideshow, hence I can only proceed knowing that all 5 downloads have been completed. 现在唯一的问题是,在下载这些资源之后,我想以幻灯片形式向用户显示它们,因此,只有知道所有5个下载都已完成,我才能继续进行。 The problem with the code above is that since the getDataFromUrl function is executed asynchronously, this while loop will finish executing before all of the content has actually been downloaded. 上面的代码的问题在于,由于getDataFromUrl函数是异步执行的,因此while循环将在所有内容实际下载之前完成执行。

EDIT 编辑

Here is a code adapting the accepted answer to uploading as well. 这也是使接受的答案也适合上传的代码。 The problem is that when more than one value is in the queue, only the first task gets executed and then nothing happens. 问题在于,当队列中有多个值时,只有第一个任务被执行,然后什么也没有发生。

 var uploadQueue:[UploadMessage]?
let session = NSURLSession.sharedSession()
let lockQueue = dispatch_queue_create("com.dsdevelop.lockQueue", nil)

func getRemainingActiveUploads() -> Int {
    return (self.uploadQueue != nil) ? self.uploadQueue!.count : 0
}

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?

func finishedUploading() {
    uploadTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(uploadAllLinks), userInfo: nil, repeats: false)
    if (needToRefetch) {
        needToRefetch = false
        newMessageReceived()
    }
}

func uploadAllLinks()
{
    print("uploading test")
    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
    }

}

Using the built in abilities of NSURLSession and its underlying NSOperationQueue you can do this easily enough. 使用NSURLSession及其基础的NSOperationQueue的内置功能,您可以很容易地做到这一点。

import UIKit

class ViewController: UIViewController {

    let MyDownloadsCompleteNotification:String = "MyDownloadsCompleteNotification"

    var myLinks:[NSURL]?
    var downloadQueue:[NSURL]?
    let session = NSURLSession.sharedSession()
    let lockQueue = dispatch_queue_create("com.dsdevelop.lockQueue", nil)

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        myLinks = [ NSURL(string: "https://pbs.twimg.com/profile_images/447374371917922304/P4BzupWu.jpeg")!,
                    NSURL(string: "http://www.telegraph.co.uk/content/dam/pets/2016/03/18/bunny-large_trans++qVzuuqpFlyLIwiB6NTmJwfSVWeZ_vEN7c6bHu2jJnT8.jpg")!,
                    NSURL(string: "http://4.bp.blogspot.com/-HTvSYzA-pO4/UgQb4Zh_u0I/AAAAAAAAEuI/XwhtogT_1tA/s1600/3+cute2.jpg")!,
                    NSURL(string: "http://cdn.shopify.com/s/files/1/0224/1915/files/bunny.jpg?22110")!,
                    NSURL(string: "http://vignette1.wikia.nocookie.net/hare/images/1/1f/Bunnies-bunny-rabbits-16437969-1280-800.jpg/revision/latest?cb=20130831183111")!
        ]


        // Register to know when all downloads are done
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(allDownloadsComplete), name: MyDownloadsCompleteNotification, object: nil)

        downloadAllLinks(myLinks!)
    }

    func allDownloadsComplete(n:NSNotification)
    {
        print("Awesome all downloads are done!")
    }

    func getRemainingActiveDownloads() -> Int
    {
        return (self.downloadQueue != nil) ? self.downloadQueue!.count : 0
    }

    func removeUrlFromDownloadQueue(url:NSURL)
    {
        if self.downloadQueue != nil
        {
            dispatch_sync(lockQueue) {
                self.downloadQueue = self.downloadQueue!.filter({$0.absoluteString == url.absoluteString})
            }
        }
    }

    func downloadAllLinks(links:[NSURL])
    {
        // suspending queue so they don't all finish before we can show it
        session.delegateQueue.suspended = true
        session.delegateQueue.maxConcurrentOperationCount = 1

        downloadQueue = links

        // create tasks
        for link in links
        {
            let dltask = session.downloadTaskWithURL(link, completionHandler: { (url, response, error) in
                if let urlString = response?.URL?.absoluteString
                {
                    self.downloadQueue = self.downloadQueue!.filter({$0.absoluteString != urlString})
                    let remaining = self.getRemainingActiveDownloads()
                    print("Downloaded.  Remaining: \(remaining)")

                    if (remaining == 0)
                    {
                        NSNotificationCenter.defaultCenter().postNotificationName(self.MyDownloadsCompleteNotification, object: nil)
                    }

                }
            })
            print("Queuing task \(dltask)")
            dltask.resume()
        }

        // resuming queue so all tasks run
        session.delegateQueue.suspended = false
    }
}

You could create a timer to check whether all 5 resources have been completely downloaded. 您可以创建一个计时器来检查所有5个资源是否都已完全下载。 Set the interval to 1ms and you will know immediately once all 5 are done. 将间隔设置为1ms,一旦完成所有5个操作,您将立即知道。

You should add a var downloadsCompletedCounter = 0 and in your completion handler you should increment this counter: 您应该添加一个var downloadsCompletedCounter = 0并在完成处理程序中增加此计数器:

self.downloadsCompletedCounter =+ 1 

Use this in the block of dispatch_async(dispatch_get_main_queue() to avoid multithreading issues. dispatch_async(dispatch_get_main_queue()的块中使用此函数,以避免多线程问题。

You can also implement a property observer for downloadsCompletedCounter so that you know exactly when the downloads complete: 您还可以为downloadsCompletedCounter实现一个属性观察器,以便确切知道下载何时完成:

var downloadsCompletedCounter = 0 {
    didSet{
        if downloadsCompletedCounter == 4 {
            print("Downloads completed")
            // call the function you want to execute after downloads complete
        }
    }
}

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

相关问题 Swift-与DispatchGroup()异步从Firebase Firestore下载数据时出现问题 - Swift - Problem While Downloading Data From Firebase Firestore Asynchronously with DispatchGroup() 快速从可选URL下载图像 - Downloading image from optional URL in swift 从 Swift 上的 URL 加载/下载图像 - Loading/Downloading image from URL on Swift Swift - Firebase - 异步下载图像和数据会导致集合视图单元格中的显示错误 - Swift - Firebase - Downloading images and data asynchronously leads to wrong display within the collection view cell Swift:从url下载数据会导致semaphore_wait_trap冻结 - Swift: downloading data from url causes semaphore_wait_trap freeze 从 Firebase 上传/下载数据时可以获得进度吗 - Can I get progress while uploading/downloading data from Firebase 从Swift上的Firebase通过URL下载时横向加载图像 - Image loading sideways upon downloading via URL from Firebase on Swift 当我从另一个 url 下载图像时,将图像上传到特定 url 的正确方法是什么? - what is the correct way of uploading image to a specific url when i am downloading a image from a another url? 快速下载URL并填充uiimageview - swift downloading url and populating uiimageview 从 Swift 中的 URL 获取数据 - getting data from URL in Swift
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM