Reputation: 163
While using Swift I want to check if an NSURL
location is a directory. With Objective-C this is not a problem and working find, but when I convert the code to Swift I run into a runtime error.
Maybe someone can point me in the right direction?
import Foundation
let defaultManager = NSFileManager.defaultManager()
let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
let localDocumentURLs = defaultManager.contentsOfDirectoryAtURL(documentsDirectory,
includingPropertiesForKeys: nil, options: .SkipsPackageDescendants, error: nil) as NSURL[]
for url in localDocumentURLs {
var isError: NSError? = nil
var isDirectory: AutoreleasingUnsafePointer<AnyObject?> = nil
var success: Bool = url.getResourceValue(isDirectory, forKey: NSURLIsDirectoryKey, error: &isError)
}
Upvotes: 12
Views: 16250
Reputation: 285270
In iOS 9.0+ and macOS 10.11+ there is a property in NSURL
/ URL
Swift:
var hasDirectoryPath: Bool { get }
Objective-C:
@property(readonly) BOOL hasDirectoryPath;
However this is only reliable for URLs created with the FileManager
API which ensures that the string path of a dictionary ends with a slash.
For URLs created with custom literal string paths reading the resource value isDirectory
is preferable
Swift:
let isDirectory = (try? url.resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory ?? false
Objective-C:
NSNumber *isDirectory = nil;
[url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil];
NSLog(@"%i", isDirectory.boolValue);
Upvotes: 36
Reputation: 188
Swift 3
extension URL {
var isDirectory: Bool {
let values = try? resourceValues(forKeys: [.isDirectoryKey])
return values?.isDirectory ?? false
}
}
Upvotes: 17
Reputation: 22773
... and this is a Swift 3 extension on FileManager
:
extension FileManager {
func isDirectory(url:URL) -> Bool? {
var isDir: ObjCBool = ObjCBool(false)
if fileExists(atPath: url.path, isDirectory: &isDir) {
return isDir.boolValue
} else {
return nil
}
}
}
Upvotes: 0
Reputation: 133199
Plenty of answers here... but they all have one thing in common:
They all use FileManager
(which is in fact NSFileManger
).
This approach has one downside: FileManager
is not thread-safe! Using a FileManager
from different threads in parallel usually works for stateless operations, but that is nowhere guaranteed (you might be building on undefined behavior when you rely that this works).
A safe implementation would have to create a new FileManager
instance every time, yet that would be horrible performance, or use one per thread, which is huge management overhead.
There's a much better, much simpler approach I'd like to present here, that doesn't need any 3rd party class:
extension URL {
var isDirectory: Bool? {
do {
let values = try self.resourceValues(
forKeys:Set([URLResourceKey.isDirectoryKey])
)
return values.isDirectory
} catch { return nil }
}
}
That's it. Using the resourceValues()
method you can also easily query other interesting information, like the size of a file or the last modification date. This is a very powerful API, that exists for ages for NSURL
in Obj-C as well.
Upvotes: 4
Reputation: 2789
Here's the swift 2.0 version of the original poster's code:
do {
var rsrc: AnyObject?
try element.getResourceValue(&rsrc, forKey: NSURLIsDirectoryKey)
if let isDirectory = rsrc as? NSNumber {
if isDirectory == true {
// ...
}
}
} catch {
}
Upvotes: 3
Reputation: 3501
my 2 cents ... swift NSURL way: (based on holex's answer)
var error: NSError?
// since getting it as URLForDirectory, it flags it as dir, for custom path: NSURL:fileURLWithPath:isDirectory:
let documentURL:NSURL = NSFileManager.defaultManager().URLForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomain: NSSearchPathDomainMask.UserDomainMask, appropriateForURL: nil, create: true, error: &error)
// passes true, if it exists and validates as dir (as flagged in the NSURL object)
if (documentURL.checkResourceIsReachableAndReturnError(&error) {
println(error)
}
Upvotes: 2
Reputation: 24031
that is working quote well on my side:
var error: NSError?
let documentURL : NSURL = NSFileManager.defaultManager().URLForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomain: NSSearchPathDomainMask.UserDomainMask, appropriateForURL: nil, create: true, error: &error)
var isDirectory: ObjCBool = ObjCBool(0)
if NSFileManager.defaultManager().fileExistsAtPath(documentURL.path, isDirectory: &isDirectory) {
println(isDirectory)
}
NOTE: it checks whether the Documents
folder is a folder. you can replace the URL with anything, of course.
Upvotes: 14