1

I'm using the FileManager for edit, move and delete files in my App. But how can be sure that the method moveItem is completed? Is there any possible callback? I read something about a FileManagerDelegate but I didn't find enough information how to use it. Thanks

Fab
  • 816
  • 8
  • 17

2 Answers2

6

The moveItem(at:to:) method is synchronous, which means that it won't move on to any lines of code afterwards until the operation is completed. In Swift, it also throws, so you know that something went wrong if it gives you an error, and everything is fine if it moves on. You should call it like this:

do{
    try FileManager.default.moveItem(at: origURL, to: newURL)
}
catch let error{
    // Handle any errors here
    dump(error)
}

In Objective-C, it returns a BOOL that specifies if the operation succeeded, and takes a pass-by-reference NSError that it will configure if something went wrong. For example:

NSError *error = nil;
BOOL success = [[NSFileManager defaultManager] moveItemAtURL:origURL toURL:newURL error:&error];
if(!success || error){
    // Something went wrong, handle the error here
}
else{
    // Everything succeeded
}
Michael Hulet
  • 3,253
  • 1
  • 16
  • 33
  • It's synchronous but you can still dispatch the work to another queue and dispatch your completion back to the main one. Check my answer. – Au Ris Jul 31 '18 at 09:33
  • You could do this, but ultimately it'd be easier/clearer/more configurable imo if you just handle the queues and whatever code afterwards at the call site – Michael Hulet Jul 31 '18 at 09:36
  • 1
    The point I am trying to make is this kind of work doesn't belong to the main thread (in my option). Where you handle your queues it's up to the developer. – Au Ris Jul 31 '18 at 09:38
2

You could extend your FileManager to add a few methods for more convenience:

extension FileManager {
    func moveItem(at url: URL, toUrl: URL, completion: @escaping (Bool, Error?) -> ()) {
        DispatchQueue.global(qos: .utility).async {

            do {
                try self.moveItem(at: url, to: toUrl)
            } catch {
                // Pass false and error to completion when fails
                DispatchQueue.main.async {
                   completion(false, error)
                }
            }

            // Pass true to completion when succeeds
            DispatchQueue.main.async {
                completion(true, nil)
            }
        }
    }
}

And call it like this:

FileManager.default.moveItem(at: atUrl, toUrl: toUrl) { (succeeded, error) in
    if succeeded {
        // Success
    } else {
        // Something went wrong
    }
}
Joannes
  • 2,569
  • 3
  • 17
  • 39
Au Ris
  • 4,541
  • 2
  • 26
  • 53