如何在 Swift 中找到 NSDocumentDirectory?

我正在尝试用代码获取“文档”文件夹的路径:

var documentsPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory:0,NSSearchPathDomainMask:0,true)

但是 Xcode 给出了错误: Cannot convert expression's type 'AnyObject[]!' to type 'NSSearchPathDirectory'

我想知道代码出了什么问题。

139877 次浏览

显然,编译器认为 NSSearchPathDirectory:0是一个数组,当然它期望的类型是 NSSearchPathDirectory。肯定不是什么有用的错误消息。

但至于原因:

首先,你把参数名称和类型搞混了,看看函数定义:

func NSSearchPathForDirectoriesInDomains(
directory: NSSearchPathDirectory,
domainMask: NSSearchPathDomainMask,
expandTilde: Bool) -> AnyObject[]!
  • directorydomainMask是名称,您使用的是类型,但无论如何都应该将它们留给函数。它们主要用于方法。
  • 另外,Swift 是强类型的,所以不应该只使用0,而应该使用枚举的值。
  • 最后,它返回一个数组,而不仅仅是一个路径。

所以我们只剩下(更新为 Swift 2.0) :

let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]

还有 Swift 3:

let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]

现在的建议是对文件和目录使用 NSURL,而不是基于 NSString 的路径:

enter image description here

因此,要获取应用程序的 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,如果初始版本不存在,则将其复制到捆绑包中,如果出现错误,则使用 nil。

对于每一个看起来与 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版本,它具有 Guard (Ruby 除非是模拟的) ,所以有了 Guard,它会更短、更易读

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
}

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 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]
}
}

迅捷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 8b4 Swift 3.0

let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)

更方便的 Swift 3方法:

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

通常我喜欢像下面的 雨燕3,因为我可以添加文件名和创建一个文件容易

let fileManager = FileManager.default
if let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
let databasePath = documentsURL.appendingPathComponent("db.sqlite3").path
print("directory path:", documentsURL.path)
print("database path:", databasePath)
if !fileManager.fileExists(atPath: databasePath) {
fileManager.createFile(atPath: databasePath, contents: nil, attributes: 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
}

像这样复制并粘贴 App 委托中的这一行,它将像这样打印路径

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
print(NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last! as String)
return true
}

复制路径并将其粘贴到 finder 中的文件夹中,右键单击它,然后输入 enter image description here

在 Xcode 打开文件

enter image description here