4

Most of my programming experience is in Shell and Python. I'm fairly new to Swift, like "3 days ago" new. I just can't figure out why didFinishDownloadtingTo is not called when my downloadTask completes. Here's my AppDelegate.swift file:

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, URLSessionDelegate, URLSessionDownloadDelegate {

@IBOutlet weak var window: NSWindow!
@IBOutlet var progressind: NSProgressIndicator!
@IBOutlet var outputtext: NSTextField!



func applicationDidFinishLaunching(_ aNotification: Notification) {

    // Insert code here to initialize your application
    let requestURL: URL = URL(string: "https://www.apple.com")!
    let urlRequest: URLRequest = URLRequest(url: requestURL as URL)
    let session = URLSession.shared
    let downloads = session.downloadTask(with: urlRequest)
    print("starting download...")
    downloads.resume()

}

func applicationWillTerminate(_ aNotification: Notification) {
    // Insert code here to tear down your application
}

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){
    print("download finished!")
}


}

I'm using Swift 3, and I just cannot find enough documentation on it to figure this out on my own.

I went a little crazy declaring classes trying to figure out why it wasn't working right, so I'm sure there are also some errors there.

It appears to download the file successfully. I've tried with several URLs. The "Disk" and "Network" sections of the debug menu appear consistent with downloading a file of the size at every URL I've tested with.

Matt
  • 65
  • 7
  • what are you trying to acheive? Just testing purpose? If you want to download things I suggest you take a look at Alamofire. Use dependency manager like Cocoapods – Andre Cytryn Aug 23 '16 at 02:36
  • I'm just trying to get a file from a static webpage. This will appear one time when the application is said and done, so downloading and learning to use an entire networking library to download one file for initial setup of an application seems a bit too complicated for me at the moment. – Matt Aug 23 '16 at 02:49

2 Answers2

9

The thing is that when you use NSURLSession(URLSession in Swift 3) you have to choose if you want to use a delegate or a completion handler, in case of use both, only the completion handler gets called. In your case the delegate is not set so you can't see the call to the delegate methods. Instead you should specify the delegate using the another initializer of NSURLSession like in the following code:

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, URLSessionDelegate, URLSessionDownloadDelegate {

   func applicationDidFinishLaunching(_ aNotification: Notification) {
      let requestURL: URL = URL(string: "https://www.apple.com")!
      let urlRequest: URLRequest = URLRequest(url: requestURL as URL)

      let config = URLSessionConfiguration.default
      let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)

      let downloads = session.downloadTask(with: urlRequest)

      print("starting download...")
      downloads.resume()
   }

   func applicationWillTerminate(_ aNotification: Notification) {
      // Insert code here to tear down your application
   }

   func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){
       print("download finished!")
   }   
}

And then you should see the delegate method called properly.

I hope this help you

Victor Sigler
  • 23,243
  • 14
  • 88
  • 105
  • That worked perfectly! This leads me to a second question. I still am not sure how delegates "link" together or work together or whatever it's called. In this case, is "self" my AppDelegate.swift file? If so, would replacing "self" with "DownloadDelegate" tell my program to look in "DownloadDelegate.swift" for a "didFinishDownloadingTo" method? – Matt Aug 23 '16 at 14:11
  • @user6684500 No, It's not the way in which the delegate pattern is handled, the delegate is very easy to understand if you see carefully, you delegate function to another objects, The delegating object keeps a reference to the other object—the delegate and at the appropriate time sends a message to it, you can read more about it [here](https://developer.apple.com/library/mac/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html). And please accept the answer if solve your question :) – Victor Sigler Aug 23 '16 at 16:16
2

The key lies in the word "delegate". It's like the dog in the night-time in the Sherlock Holmes story. The dog did nothing in the night. The word "delegate" never appears in your code!

But it needs to. didFinishDownloadingTo is a delegate method. You can only receive this method if you are the delegate of the NSURLSession. You need to set self as its delegate. The runtime doesn't magically read your mind and know that you intend this object as the delegate; you have to tell it.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Yes indeed @matt, but the thing is that he is using the `URLSession.shared` and as the `delegate` in the `URLSession` is read-only it's impossible to do it in that way at least. – Victor Sigler Aug 23 '16 at 03:24
  • 1
    @VictorSigler Perfectly true. I'm just trying to get the concept clear. The question was "I just can't figure out why `didFinishDownloadtingTo` is not called". And the answer is what I said: it's because you are not the delegate. I didn't say your answer is wrong (though in fact your talk about the completion handler is completely wide of the mark). Your answer has the benefit of telling the OP what _to do_. But my answer has the benefit of answering the question the OP actually asked. The world is large enough for both, methinks. – matt Aug 23 '16 at 03:49
  • @matt I have included the didFinishDownloadingTo in my appDelegate and when configuring my session, I do set the delegate to self but I am still not getting into that method. Any other ideas why else the delegate method would not get called? Full details here: http://stackoverflow.com/questions/41488989/using-urlsession-and-background-fetch-together-with-remote-notifications-using-f – user2363025 Jan 05 '17 at 17:44