我正在尝试使用代码获取Documents文件夹的路径:
var documentsPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory:0,NSSearchPathDomainMask:0,true)
但Xcode给出了错误: Cannot convert expression's type 'AnyObject[]!' to type 'NSSearchPathDirectory'
我试图了解代码中的错误.
显然,编译器认为NSSearchPathDirectory:0
是一个数组,当然它期望类型NSSearchPathDirectory
.当然不是一个有用的错误消息.
但至于原因:
首先,您会混淆参数名称和类型.看一下函数定义:
func NSSearchPathForDirectoriesInDomains( directory: NSSearchPathDirectory, domainMask: NSSearchPathDomainMask, expandTilde: Bool) -> AnyObject[]!
directory
并且domainMask
是名称,您使用的是类型,但是无论如何都应该将它们留给函数.它们主要用于方法.
此外,Swift是强类型的,所以你不应该只使用0.使用枚举的值代替.
最后,它返回一个数组,而不仅仅是一个路径.
这样就离开了我们(为Swift 2.0更新):
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
对于Swift 3:
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
现代建议使用NSURLs代替基于NSString的路径的文件和目录:
因此,要将应用程序的Document目录作为NSURL获取:
func databaseURL() -> NSURL? { let fileManager = NSFileManager.defaultManager() let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) if let documentDirectory: NSURL = urls.first as? NSURL { // This is where the database should be in the documents directory let finalDatabaseURL = documentDirectory.URLByAppendingPathComponent("items.db") if finalDatabaseURL.checkResourceIsReachableAndReturnError(nil) { // The file already exists, so just return the URL return finalDatabaseURL } else { // Copy the initial file from the application bundle to the documents directory if let bundleURL = NSBundle.mainBundle().URLForResource("items", withExtension: "db") { let success = fileManager.copyItemAtURL(bundleURL, toURL: finalDatabaseURL, error: nil) if success { return finalDatabaseURL } else { println("Couldn't copy file to final location!") } } else { println("Couldn't find initial database in the bundle!") } } } else { println("Couldn't get documents directory!") } return nil }
这有一个基本的错误处理,因为这取决于你的应用程序在这种情况下会做什么.但是这会使用文件URL和更现代的api来返回数据库URL,如果它不存在则将初始版本复制到bundle之外,或者在出现错误时将其复制为nil.
Swift 3.0和4.0
如果找不到路径,直接从数组中获取第一个元素可能会导致异常.所以调用first
然后解包是更好的解决方案
if let documentsPathString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first { //This gives you the string formed path } if let documentsPathURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first { //This gives you the URL of the path }
通常我会首先使用此扩展名:
Swift 3.x和Swift 4.0:
extension FileManager { class func documentsDir() -> String { var paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as [String] return paths[0] } class func cachesDir() -> String { var paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true) as [String] return paths[0] } }
Swift 2.x:
extension NSFileManager { class func documentsDir() -> String { var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as [String] return paths[0] } class func cachesDir() -> String { var paths = NSSearchPathForDirectoriesInDomains(.CachesDirectory, .UserDomainMask, true) as [String] return paths[0] } }
Xcode 8.2.1•Swift 3.0.2
let documentDirectoryURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
Xcode 7.1.1•Swift 2.1
let documentDirectoryURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
对于看起来与Swift 2.2一起使用的示例的每个人,使用现代的Abizern代码尝试捕获错误句柄
func databaseURL() -> NSURL? { let fileManager = NSFileManager.defaultManager() let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) if let documentDirectory:NSURL = urls.first { // No use of as? NSURL because let urls returns array of NSURL // This is where the database should be in the documents directory let finalDatabaseURL = documentDirectory.URLByAppendingPathComponent("OurFile.plist") if finalDatabaseURL.checkResourceIsReachableAndReturnError(nil) { // The file already exists, so just return the URL return finalDatabaseURL } else { // Copy the initial file from the application bundle to the documents directory if let bundleURL = NSBundle.mainBundle().URLForResource("OurFile", withExtension: "plist") { do { try fileManager.copyItemAtURL(bundleURL, toURL: finalDatabaseURL) } catch let error as NSError {// Handle the error print("Couldn't copy file to final location! Error:\(error.localisedDescription)") } } else { print("Couldn't find initial database in the bundle!") } } } else { print("Couldn't get documents directory!") } return nil }
更新 我错过了新的swift 2.0有防范(Ruby除非是模拟),所以有了防范它更短更可读
func databaseURL() -> NSURL? { let fileManager = NSFileManager.defaultManager() let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) // If array of path is empty the document folder not found guard urls.count != 0 else { return nil } let finalDatabaseURL = urls.first!.URLByAppendingPathComponent("OurFile.plist") // Check if file reachable, and if reacheble just return path guard finalDatabaseURL.checkResourceIsReachableAndReturnError(nil) else { // Check if file is exists in bundle folder if let bundleURL = NSBundle.mainBundle().URLForResource("OurFile", withExtension: "plist") { // if exist we will copy it do { try fileManager.copyItemAtURL(bundleURL, toURL: finalDatabaseURL) } catch let error as NSError { // Handle the error print("File copy failed! Error:\(error.localizedDescription)") } } else { print("Our file not exist in bundle folder") return nil } return finalDatabaseURL } return finalDatabaseURL }
更方便的Swift 3方法:
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
Xcode 8b4 Swift 3.0
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)