¿Cómo encontrar NSDocumentDirectory en swift?

Estoy tratando de obtener una ruta a la carpeta Documentos con el código:

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

pero xcode da error: No se puede convertir el tipo de expresión ‘AnyObject []!’ escribir ‘NSSearchPathDirectory’

Estoy tratando de entender lo que está mal en el código?

Aparentemente, el comstackdor cree que NSSearchPathDirectory:0 es una matriz y, por supuesto, espera el tipo NSSearchPathDirectory en NSSearchPathDirectory lugar. Ciertamente no es un mensaje de error útil.

Pero en cuanto a las razones:

En primer lugar, está confundiendo los nombres y tipos de argumentos. Eche un vistazo a la definición de la función:

 func NSSearchPathForDirectoriesInDomains( directory: NSSearchPathDirectory, domainMask: NSSearchPathDomainMask, expandTilde: Bool) -> AnyObject[]! 
  • directory y domainMask son los nombres, usted está usando los tipos, pero debe dejarlos fuera para funciones de todos modos. Se usan principalmente en métodos.
  • Además, Swift está fuertemente tipado, por lo que no debería usar simplemente 0. Use el valor de la enumeración en su lugar.
  • Y finalmente, devuelve una matriz, no solo una ruta única.

Eso nos deja con (actualizado para Swift 2.0):

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

y para Swift 3:

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

La recomendación moderna es usar NSURL para archivos y directorios en lugar de rutas basadas en NSString:

enter image description here

Entonces, para obtener el directorio del documento para la aplicación como 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 } 

Esto tiene un manejo de errores rudimentario, ya que depende de lo que su aplicación hará en tales casos. Pero esto utiliza URLs de archivos y una API más moderna para devolver la URL de la base de datos, copiando la versión inicial del paquete si aún no existe, o una nula en caso de error.

Swift 3.0 y 4.0

Conseguir directamente el primer elemento de una matriz provocará una excepción si la ruta no se encuentra. Entonces, llamar first y luego desenvolver es la mejor solución

 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 } 

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) 

Por lo general, prefiero usar esta extensión:

Swift 3.xy 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] } } 

Para todos los que vean ejemplos que funcionen con Swift 2.2, el código de Abizern con el moderno intentan capturar el identificador de error

 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 } 

Actualización Me he perdido ese nuevo swift 2.0 have guard (Ruby a menos que sea analógico), así que con guardian es mucho más corto y más legible

 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 } 

Método más conveniente 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) 

Usualmente prefiero el siguiente en Swift 3 , porque puedo agregar un nombre de archivo y crear un archivo fácilmente

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