how to check if a file is in trash or not

iOS 12.1.0 + Xcode 10.1


I am using URLs with bookmarks to keep recents.


When I trashed a file, its bookmark results a URL in a trash.


If the trashed file was located in my iPad, I can check if the file is in the current user's trash.


do {

var relationship = FileManager.URLRelationship.other

try FileManager.default.getRelationship(&relationship, ofDirectoryAt: trashUrl, toItemAt: url)

if relationship == .contains {

return true

}

} catch {

print(error.localizedDescription)

}


If the trashed file was in iCloud or any other clouds, how can I check if the file is in trash or not?


Thank you~ ^^

Accepted Reply

Is there any better way?

I’m not sure, but any way that involves hard coding

.Trash
is not good.
.trashDirectory
for SearchPathDirectory does not work

When dealing with the trash it’s critical that you call a routine, like

url(for:in:appropriateFor:create:)
, that lets you pass in an ‘appropriate URL’ parameter, because the trash can be different for different parts of the file system.

Share and Enjoy

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

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

Replies

In this code snippet, how are you calculating

trashUrl
?

Share and Enjoy

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

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

let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)

let trashUrl = urls.first!.appendingPathComponent(".Trash")


Is there any better way? .trashDirectory for SearchPathDirectory does not work so that I had to do above codes...

Is there any better way?

I’m not sure, but any way that involves hard coding

.Trash
is not good.
.trashDirectory
for SearchPathDirectory does not work

When dealing with the trash it’s critical that you call a routine, like

url(for:in:appropriateFor:create:)
, that lets you pass in an ‘appropriate URL’ parameter, because the trash can be different for different parts of the file system.

Share and Enjoy

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

let myEmail = "eskimo" + "1" + "@apple.com"
The documentation for getRelationship says: “For example, to discover if a file is contained by a Trash directory, call [fileManager getRelationship:&result ofDirectory:NSTrashDirectory inDomain:0 toItemAtURL:url error:&error].” However, I can’t get the following Swift code to work:

Code Block
    var relationship: URLRelationship = .contains
    getRelationship(&relationship, of: .trashDirectory,
                                in: SearchPathDomainMask(rawValue: 0),
                                toItemAt: url)

After finding your comment above, I tried using url(for:in:appropriateFor:create:) to get the trash directory, but can’t get that to work either (iOS 14.0.1, Xcode 12.0.1). The following code always fails with "The requested operation couldn’t be completed because the feature is not supported.":

Code Block
    let fileManager = FileManager.default
    let docURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
    do {
        let trashURL = try fileManager.url(for: .trashDirectory, in: .userDomainMask,
                                           appropriateFor: docURL, create: false)
        print("trashURL = \(trashURL)")
    }
    catch {
        print("could not get trashURL: \(error.localizedDescription)")
    }

Is this API not working, or am I doing something wrong? Thanks!

However, I can’t get the following Swift code to work:

How does it fail?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
The following works well for me when trashing a file which is on my primary disk. It also works when the file is on an SMB network volume, where the Finder's trashing confirmation message says "This item will be deleted immediately." I'm reasonably sure it's not inside any hidden folder in the latter case, and so I wouldn't say it's "In the trash", but whatever :)

Code Block swift
extension FileManager {
    public func isInTrash(_ file: URL) -> Bool {
        var relationship: URLRelationship = .other
        try? getRelationship(
            &relationship,
            of: .trashDirectory,
            in: .allDomainsMask,
            toItemAt: file
        )
        return relationship == .contains
    }
}


Unfortunately when I trash a file which is on an external disk (in my test case an SD Card), the above returns false. Any thoughts on how to detect this edge case?

Any thoughts on how to detect this edge case?

Well, you should start by filing a bug. The whole point of getRelationship(_:of:in:toItemAt:) is that you shouldn’t have to write the messy code required to answer this question yourself.

Please post your bug number, just for the record.

Note I thought that this might be related to the mandatory access control we added to the removable volumes in recent systems (System Preferences > Security & Privacy > Privacy > Files and Folders > YourAppName > Removable Volumes), but getRelationship(_:of:in:toItemAt:) returns the wrong result even if the app has that privilege.

As to a workaround, it seems that calling url(for:in:appropriateFor:create:) to get the .trashDirectory and then calling getRelationship(_:ofDirectoryAt:toItemAt:) does the trick.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"