草庐IT

ios - Swift - NSURLSession 恢复后完成操作

coder 2023-09-16 原文

我正在尝试在 URLSession 恢复后完成一个操作。

所以我使用 url 从我的服务器下载了几张图片,一切正常。但是现在我正在尝试在完成下载后将这些图像保存到磁盘。

问题

现在我可以在下载它们的同时将它们保存在同一个查询中,但我不希望太多,因为它会使我的查询变慢。

因此,我已经通过查询向我的 func 添加了一个完成处理程序,但是当我将图像保存到该 block 中的磁盘时,它可以工作但是我无法对我的屏幕执行任何操作,因为查询尚未恢复但它被阻止了触摸我猜...

现在我希望能够在恢复查询后立即调用我的函数将图像保存到磁盘....任何人有任何想法吗?

如果有人需要更多解释或查看代码,请在下面发表评论

非常感谢任何可以提供帮助的人!

下载代码

func loadPosts(completionHandler: @escaping (Bool) -> ()) {

        pageNumber = 1
        appDelegate.setNetworkActivityIndicatorVisible(true)

        let id = user!["id"] as! String
        let url = URL(string: "http://************/Files/Posts.php")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        let body = "id=\(id)&caption=&uuid=&page="
        request.httpBody = body.data(using: String.Encoding.utf8)
        let task = URLSession.shared.dataTask(with: request, completionHandler: { (data:Data?, response:URLResponse?, error:Error?) in

            DispatchQueue.global(qos: .background).async {
                if error == nil {

                    let oldImageArray = self.cellContentArray
                    self.cellContentArray.removeAll(keepingCapacity: false)


                    do {
                        let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary

                         guard let parseJSON = json else {
                            print("Error while parsing")
                            return
                        }
                        guard let posts = parseJSON["Posts"] as? [AnyObject] else {
                            print("Error while parseJSONing")
                           return
                        }
                        for element in posts {
                            // here I download the stuff and it to my Array, too long and no point to show here

                        }

                        let oldImageSet = Set(oldImageArray.map({return $0.uuid}))
                        let newImageSet = Set(self.cellContentArray.map({return $0.uuid}))
                        let addedImages = newImageSet.subtracting(oldImageSet)
                        let addedImageSections = Array(addedImages).map{ self.cellContentArray.map({return $0.uuid}).index(of: $0)! }
                        let addedImageIndexSet = IndexSet(addedImageSections)
                        let removedImages = oldImageSet.subtracting(newImageSet)
                        let removedImageSections = Array(removedImages).map{ oldImageArray.map({return $0.uuid}).index(of: $0)! }
                        let removedImageIndexSet = IndexSet(removedImageSections)


                        if !addedImageIndexSet.isEmpty {
                            if oldImageArray.count >= 5 {
                            self.lastUUIDImage = oldImageArray[4].uuid
                            } else {

                            }
                            self.coreDataShit()
                        }
                        DispatchQueue.main.async{
                            print(placeholderImage.count)
                            if placeholderImage.count > 5 {
                                placeholderImage.removeFirst(placeholderImage.count - 5)
                            }
                            print("finished")
                            self.customView.isHidden = true
                            if posts.count >= 5 {
                                self.tableView.addInfiniteScroll { [weak self] (scrollView) -> Void in
                                    self?.loadMore()
                                }}
                            self.activityView.stopAnimating()
                            self.internetView.removeFromSuperview()



                          self.tableView.beginUpdates()
                            if !addedImageIndexSet.isEmpty {
                                self.tableView.insertSections(addedImageIndexSet, with: .top)
                            }
                            if !removedImageIndexSet.isEmpty {
                                self.tableView.deleteSections(removedImageIndexSet, with: .bottom)
                            }
                            self.tableView.endUpdates()
                            self.tableView.finishInfiniteScroll()
                            self.refresher.endRefreshing()
                            appDelegate.setNetworkActivityIndicatorVisible(false)
                            completionHandler(true)

                       }
                    } catch {
                        DispatchQueue.main.async {
                            self.tableView.removeInfiniteScroll()
                            self.customView.isHidden = false
                            self.refresher.endRefreshing()
                            self.tableView.reloadData()
                        }
                    }


                } else {
                    DispatchQueue.main.async(execute: {
                        let message = error!.localizedDescription
                        appDelegate.infoView(message: message, color: smoothRedColor)
                    })
                }
            }
        })
        task.resume()

    }

保存图片

   self.loadPosts(completionHandler: { (true) in
                print("completion")

                let sections = self.tableView.numberOfSections
                for i in 0..<sections {
                    self.rows += self.tableView.numberOfRows(inSection: i)
                }

                print(self.rows)

                if self.rows <= 5 {
                    print("less than 5")
                    print(self.rows)
                    var i = 0

                    for element in self.cellContentArray {

                        let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
                        let dirPath = "\(path)/images"
                        let url = NSURL(fileURLWithPath: dirPath)
                        let filePath = url.appendingPathComponent("\(element.uuid).jpg")?.path
                        let fileManager = FileManager.default
                        if fileManager.fileExists(atPath: filePath!) {
                            print("File exsists")

                        } else {
                            print("File doesn't exsist")
                            DispatchQueue.main.async {

                                let url = NSURL(string: element.fullImage!)! // convert path str to url
                                let imageData = NSData(contentsOf: url as URL) // get data via url and assigned imageData
                                let imageName = element.uuid
                                let saveImages = FileSaveHelper(fileName: imageName, fileExtension: .JPG, subDirectory: "images", directory: .documentDirectory)
                                do {
                                    guard let image = UIImage.sd_image(with: imageData as Data!) else {
                                        print("Error getting image")
                                        return
                                    }
                                    try saveImages.saveFile(image: image)
                                    self.saveNewImagePath(imageLink: imageName, uuid: imageName)
                                    self.removeImage(itemName: "file\(i)", fileExtension: "jpg")
                                    self.removeImage(itemName: self.lastUUIDImage, fileExtension: "jpg")

                                    i += 1

                                } catch {
                                    print(error)
                                }
                            }
                        }

                    }
                }

            })

tableView 单元格中的图像

 self.postImage.sd_setImage(with: URL(string: content.fullImage!), placeholderImage: placeHolder, options: .retryFailed) { (image:UIImage?, error:Error?, cached:SDImageCacheType, url:URL?) in

           }

最佳答案

在您保存图像的代码中,这行代码阻塞了您的 UI

let imageData = NSData(contentsOf: url as URL) // get data via url and assigned imageData

这不是从服务器下载图片的正确方法,您应该使用 URLSession 异步下载图片

关于ios - Swift - NSURLSession 恢复后完成操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40821431/

有关ios - Swift - NSURLSession 恢复后完成操作的更多相关文章

  1. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  2. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  3. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  4. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  5. ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前? - 2

    我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?

  6. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

    在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

  7. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  8. ruby - 在 Ruby 中是否有一种惯用的方法来操作 2 个数组? - 2

    a=[3,4,7,8,3]b=[5,3,6,8,3]假设数组长度相同,是否有办法使用each或其他一些惯用方法从两个数组的每个元素中获取结果?不使用计数器?例如获取每个元素的乘积:[15,12,42,64,9](0..a.count-1).eachdo|i|太丑了...ruby1.9.3 最佳答案 使用Array.zip怎么样?:>>a=[3,4,7,8,3]=>[3,4,7,8,3]>>b=[5,3,6,8,3]=>[5,3,6,8,3]>>c=[]=>[]>>a.zip(b)do|i,j|c[[3,5],[4,3],[7,6],

  9. ruby-on-rails - 如何让 Rails View 返回其关联的操作名称? - 2

    我有一个非常简单的Controller来管理我的Rails应用程序中的静态页面:classPagesController我怎样才能让View模板返回它自己的名字,这样我就可以做这样的事情:#pricing.html.erb#-->"Pricing"感谢您的帮助。 最佳答案 4.3RoutingParametersTheparamshashwillalwayscontainthe:controllerand:actionkeys,butyoushouldusethemethodscontroller_nameandaction_nam

  10. Ruby:行 "m = Hash.new {|h,k| h[k] = []}"完成了什么而 "Hash.new"没有完成? - 2

    一边学习thisRailscast我从Rack中看到了以下源代码:defself.middleware@middleware||=beginm=Hash.new{|h,k|h[k]=[]}m["deployment"].concat[[Rack::ContentLength],[Rack::Chunked],logging_middleware]m["development"].concatm["deployment"]+[[Rack::ShowExceptions],[Rack::Lint]]mendend我的问题是关于第三行。什么是传递block{|h,k|h[k]=[]}到Has

随机推荐