Filemanager file copy progress with cancel ?

Not sure if I have to do this programmatically or if there is something I should specifically use but I want to display a Progress Indicator when copying / moving files including the ability to cancel ?


Also making the copy Async.


(local hdd not web)

Replies

Getting progress for a file copy operation is surprisingly tricky, as discussed in this post.

With regards cancellation, you have a couple of options:

  • At the

    FileManager
    level, you can implement the
    fileManager(_:shouldCopyItemAt:to:)
    delegate method and just continuously return false when you want to cancel.
  • With the lower-level

    copyfile
    API (learn more about this in its man page), your callback function can return
    COPYFILE_QUIT
    .

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I forgot this post existed ... How can I blast "shouldCopyItemAt" ? There's no way to send a bool.

How can I blast

shouldCopyItemAt
?

I don’t understand what “blast” means in this context.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

As you said "just continuously return false when you want to cancel."

You are implementing a delegate method, which means you have access to instance properties. Add an instance property called

shouldContinue
, set it up to true, and then, when you want to cancel, change it to false.

The only gotcha relates to threads. If you want to use another thread to cancel, you’ll have to protect this property with a lock.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Still not sure what you mean, the FileManagerDelegate doesn't have this property. If I set up a property without overriding anything what is it's dependency ?

Just have to check ... Are you meaning this will cancel the current copy or the next ?

I’m suggesting something like this:

class Copier: NSObject, FileManagerDelegate {

    init(source: URL, destination: URL) {
        self.source = source
        self.destination = destination
        self.fm = FileManager()
        super.init()
        self.fm.delegate = self
    }

    let source: URL
    let destination: URL
    private let fm: FileManager
    private let shouldContinue = true

    func run() throws {
        try fm.copyItem(at: self.source, to: self.destination)
    }

    func fileManager(_ fileManager: FileManager, shouldCopyItemAt srcURL: URL, to dstURL: URL) -> Bool {
        return self.shouldContinue
    }
}

Please note that I haven’t tested this (busy with WWDC stuff this week).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks, I would let you know how it gets on but encountered a problem when trying to copy from an External HDD. I tried a local to local file but I don't have a file big enough for it to take enough time, however the problem is it seems to hang / freeze the iMac I thought had crashed it but after waiting long enough carries on, and the file does actually copy.


I was on an earlier version of both XCode & Swift, I think was 10.1 and 4.2, up until not long ago. I used copy & move and both worked fine before and no idea what the problem could be.


Any advice ?

...

I reinstalled XCode but still having same problem, although with Swift 5 temporarily hangs the whole UI (finder etc.) but with 4.2 only the App.

...

Another update, when copying from Local HDD to External everything works fine.

...

The method to cancel unfortunately does not work for file in transit because it's only called once at start.

...

Also don't know if it's related but loading time for AVMetadata is much slower.

...

Last test, between external volumes also works fine. The hang seems to last as long as it does to copy the file, so it seems as if it's copying it twice.

Yea, the delegate method on NSFileManager really won't work for canceling unless you are copying a directory. Only thing I can think of at the NSFIleManager API level is to try to remove the file while it's still being copied to get the -copyItemAtURL:toURL:error: method to fail with an error.