ios - Swift 3 : How to sequential process download files and open ViewController -


i want click button, download number of files sequentially , after complete download, open webview display. encounter download files not completed webview opened. saw approach in days , don't know how fix problem. can help?

many thanks.

downloadmanager class

class downloadmanager: nsobject {      /// dictionary of operations, keyed `taskidentifier` of `urlsessiontask`      fileprivate var operations = [int: downloadoperation]()      /// serial nsoperationqueue downloads      private let queue: operationqueue = {         let _queue = operationqueue()         _queue.name = "download"         _queue.maxconcurrentoperationcount = 1    // i'd use values 3 or 4 performance reasons, op asked downloading 1 @ time          return _queue     }()      /// delegate-based nsurlsession downloadmanager      lazy var session: urlsession = {         let configuration = urlsessionconfiguration.default         return urlsession(configuration: configuration, delegate: self, delegatequeue: nil)     }()      /// add download     ///     /// - parameter url:  url of file downloaded     ///     /// - returns:        downloadoperation of operation queued      @discardableresult     func adddownload(_ url: url) -> downloadoperation {         let operation = downloadoperation(session: session, url: url)         operations[operation.task.taskidentifier] = operation         queue.addoperation(operation)         return operation     }      /// cancel queued operations      func cancelall() {         queue.cancelalloperations()     }  }  // mark: urlsessiondownloaddelegate methods  extension downloadmanager: urlsessiondownloaddelegate {      func urlsession(_ session: urlsession, downloadtask: urlsessiondownloadtask, didfinishdownloadingto location: url) {         operations[downloadtask.taskidentifier]?.urlsession(session, downloadtask: downloadtask, didfinishdownloadingto: location)     }      func urlsession(_ session: urlsession, downloadtask: urlsessiondownloadtask, didwritedata byteswritten: int64, totalbyteswritten: int64, totalbytesexpectedtowrite: int64) {         operations[downloadtask.taskidentifier]?.urlsession(session, downloadtask: downloadtask, didwritedata: byteswritten, totalbyteswritten: totalbyteswritten, totalbytesexpectedtowrite: totalbytesexpectedtowrite)     } }  // mark: urlsessiontaskdelegate methods  extension downloadmanager: urlsessiontaskdelegate {      func urlsession(_ session: urlsession, task: urlsessiontask, didcompletewitherror error: error?)  {         let key = task.taskidentifier         operations[key]?.urlsession(session, task: task, didcompletewitherror: error)         operations.removevalue(forkey: key)     }  }  /// asynchronous operation subclass downloading  class downloadoperation : asynchronousoperation {     let task: urlsessiontask      init(session: urlsession, url: url) {         task = session.downloadtask(with: url)         super.init()     }      override func cancel() {         task.cancel()         super.cancel()     }      override func main() {         task.resume()     } }  // mark: nsurlsessiondownloaddelegate methods  extension downloadoperation: urlsessiondownloaddelegate {      func urlsession(_ session: urlsession, downloadtask: urlsessiondownloadtask, didfinishdownloadingto location: url) {         {             let manager = filemanager.default             let destinationurl = try manager.url(for: .documentdirectory, in: .userdomainmask, appropriatefor: nil, create: false)                 .appendingpathcomponent(downloadtask.originalrequest!.url!.lastpathcomponent)             if manager.fileexists(atpath: destinationurl.path) {                 try manager.removeitem(at: destinationurl)             }             try manager.moveitem(at: location, to: destinationurl)         } catch {             print("\(error)")         }     }      func urlsession(_ session: urlsession, downloadtask: urlsessiondownloadtask, didwritedata byteswritten: int64, totalbyteswritten: int64, totalbytesexpectedtowrite: int64) {         let progress = double(totalbyteswritten) / double(totalbytesexpectedtowrite)         print("\(downloadtask.originalrequest!.url!.absolutestring) \(progress)")     } }  // mark: nsurlsessiontaskdelegate methods  extension downloadoperation: urlsessiontaskdelegate {      func urlsession(_ session: urlsession, task: urlsessiontask, didcompletewitherror error: error?)  {         completeoperation()         if error != nil {             print("\(error)")         }     }  }  /// asynchronous operation base class /// /// abstract class performs of necessary kvn of `isfinished` , /// `isexecuting` concurrent `operation` subclass. can subclass , /// implement asynchronous operations. must is: /// /// - override `main()` tasks initiate asynchronous task; /// /// - call `completeoperation()` function when asynchronous task done; /// /// - optionally, periodically check `self.cancelled` status, performing clean-up ///   necessary , ensuring `completeoperation()` called; or ///   override `cancel` method, calling `super.cancel()` , cleaning-up ///   , ensuring `completeoperation()` called.  public class asynchronousoperation : operation {      override public var isasynchronous: bool { return true }      private let statelock = nslock()      private var _executing: bool = false     override private(set) public var isexecuting: bool {         {             return statelock.withcriticalscope { _executing }         }         set {             willchangevalue(forkey: "isexecuting")             statelock.withcriticalscope { _executing = newvalue }             didchangevalue(forkey: "isexecuting")         }     }      private var _finished: bool = false     override private(set) public var isfinished: bool {         {             return statelock.withcriticalscope { _finished }         }         set {             willchangevalue(forkey: "isfinished")             statelock.withcriticalscope { _finished = newvalue }             didchangevalue(forkey: "isfinished")         }     }      /// complete operation     ///     /// result in appropriate kvn of isfinished , isexecuting      public func completeoperation() {         if isexecuting {             isexecuting = false         }          if !isfinished {             isfinished = true         }     }      override public func start() {         if iscancelled {             isfinished = true             return         }          isexecuting = true          main()     } }  /*  copyright (c) 2015 apple inc. rights reserved.  see license.txt sample’s licensing information   abstract:  extension `nslock` simplify executing critical code.   advanced nsoperations sample code in wwdc 2015 https://developer.apple.com/videos/play/wwdc2015/226/  https://developer.apple.com/sample-code/wwdc/2015/downloads/advanced-nsoperations.zip  */  extension nslock {      /// perform closure within lock.     ///     /// extension `nslock` simplify executing critical code.     ///     /// - parameter block: closure performed.      func withcriticalscope<t>(block: () -> t) -> t {         lock()         let value = block()         unlock()         return value     } } 

then, call below code when click download button.

func downloadfiles() {      {          var localjson: json?         let serverjson = self.serverjson         let str = serverjson?.description         let data = str?.data(using: .utf8)          let filemanager = filemanager.default         let documentsurl = filemanager.default.urls(for: .documentdirectory, in: .userdomainmask).first! url          let oldmanifesturl = documentsurl.appendingpathcomponent("manifest.json")         let oldmanifestpath = oldmanifesturl.path           if filemanager.fileexists(atpath: oldmanifestpath) {              let jsondata = nsdata(contentsoffile:oldmanifestpath)             localjson = json(data: jsondata! data)         }           var totalcount = 0          let downloadmanager = downloadmanager()           (index, subjson): (string, json) in serverjson! {              (_, subjson): (string, json) in subjson {                 let filepath = subjson["path"].stringvalue                 let nupdated = subjson["updated"].stringvalue                  if let oupdated = localjson?[index].array?.filter({ $0["path"].string == filepath}).first?["updated"].stringvalue {                     if (oupdated == nupdated) { continue }                 }                   var abspath = filepath                  let stridx = abspath.index(abspath.startindex, offsetby: 2)                   if (abspath.hasprefix("./"))                 {                     abspath = abspath.substring(from: stridx)                 }                   let sourceurl = url(string: self.sourceurl.appending(abspath))                  downloadmanager.adddownload(sourceurl!)               }          }          // remove temp json file first if exists.         if filemanager.fileexists(atpath: oldmanifestpath) {             try? filemanager.removeitem(atpath: oldmanifestpath)         }          // write temp json file local.         try data?.write(to: oldmanifesturl)          self.defaults.set(hashes, forkey: "lasthash")          let alertcontroller = uialertcontroller(title: "information", message: "download completed", preferredstyle: uialertcontrollerstyle.alert)         alertcontroller.addaction(uialertaction(title: "ok", style: uialertactionstyle.default, handler: nil))         self.present(alertcontroller, animated: true, completion: {              self.openwebview()           })      } catch {         print("write json data file failed, \(error.localizeddescription)")     }  } 

what need promise library offers code execution on completion conditions. currently, make request , open webview straight away. requests take time load code doesn't tell device wait requests finish before opening webview. can use promisekit purpose. library, can send multiple requests asynchronously , open webview when of requests have been processed. have explore in order understand how works. basically, code structure this

var promisearray = [promise<void>]() whatever condition want use loop {     let promise = request goes here     promisearray.append(promise) } _ = when(fulfilled: promisearray).then {     open webview here } 

Comments

Popular posts from this blog

resizing Telegram inline keyboard -

command line - How can a Python program background itself? -

php - "cURL error 28: Resolving timed out" on Wordpress on Azure App Service on Linux -