ios 如何在 Swift 中找到 NSDocumentDirectory?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24055146/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:29:49  来源:igfitidea点击:

How to find NSDocumentDirectory in Swift?

iosswiftnsdocumentdirectory

提问by Ivan R

I'm trying to get path to Documents folder with code:

我正在尝试使用代码获取 Documents 文件夹的路径:

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

but Xcode gives error: Cannot convert expression's type 'AnyObject[]!' to type 'NSSearchPathDirectory'

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

I'm trying to understand what is wrong in the code.

我试图了解代码中有什么问题。

回答by nschum

Apparently, the compiler thinks NSSearchPathDirectory:0is an array, and of course it expects the type NSSearchPathDirectoryinstead. Certainly not a helpful error message.

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

But as to the reasons:

但至于原因:

First, you are confusing the argument names and types. Take a look at the function definition:

首先,您混淆了参数名称和类型。看一下函数定义:

func NSSearchPathForDirectoriesInDomains(
    directory: NSSearchPathDirectory,
    domainMask: NSSearchPathDomainMask,
    expandTilde: Bool) -> AnyObject[]!
  • directoryand domainMaskare the names, you are using the types, but you should leave them out for functions anyway. They are used primarily in methods.
  • Also, Swift is strongly typed, so you shouldn't just use 0. Use the enum's value instead.
  • And finally, it returns an array, not just a single path.
  • directorydomainMask是名称,您正在使用类型,但无论如何您应该将它们留在函数中。它们主要用于方法中。
  • 此外,Swift 是强类型的,所以你不应该只使用 0。而是使用枚举的值。
  • 最后,它返回一个数组,而不仅仅是一个路径。

So that leaves us with (updated for Swift 2.0):

所以这给我们留下了(针对 Swift 2.0 更新):

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

and for Swift 3:

对于 Swift 3:

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

回答by Fangming

Swift 3.0 and 4.0

斯威夫特 3.0 和 4.0

Directly getting first element from an array will potentially cause exception if the path is not found. So calling firstand then unwrap is the better solution

如果找不到路径,直接从数组中获取第一个元素可能会导致异常。所以调用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
}

回答by Abizern

The modern recommendation is to use NSURLs for files and directories instead of NSString based paths:

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

enter image description here

在此处输入图片说明

So to get the Document directory for the app as an NSURL:

因此,要获取应用程序的 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
}

This has rudimentary error handling, as that sort of depends on what your application will do in such cases. But this uses file URLs and a more modern api to return the database URL, copying the initial version out of the bundle if it does not already exist, or a nil in case of error.

这具有基本的错误处理,因为这取决于您的应用程序在这种情况下会做什么。但这使用文件 URL 和更现代的 api 来返回数据库 URL,如果它不存在,则从包中复制初始版本,或者在出现错误时复制 nil。

回答by Leo Dabus

Xcode 8.2.1 ? Swift 3.0.2

Xcode 8.2.1 ? 斯威夫特 3.0.2

let documentDirectoryURL =  try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)

Xcode 7.1.1 ? Swift 2.1

Xcode 7.1.1 ? 斯威夫特 2.1

let documentDirectoryURL =  try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)

回答by Alessandro Ornano

Usually I prefeer to use this extension:

通常我更喜欢使用这个扩展:

Swift 3.x and Swift 4.0:

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:

斯威夫特 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]
    }
}

回答by Roman Safin

For everyone who looks example that works with Swift 2.2, Abizern code with modern do try catch handle of error

对于每个看起来适用于 Swift 2.2 的示例,使用现代的 Abitern 代码尝试捕获错误句柄

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
}

UpdateI've missed that new swift 2.0 have guard(Ruby unless analog), so with guard it is much shorter and more readable

更新我错过了新的 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 
}

回答by Andrey Gordeev

More convenient Swift 3method:

更方便的Swift 3方法:

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

回答by Siavash Alp

Xcode 8b4 Swift 3.0

Xcode 8b4 斯威夫特 3.0

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

回答by do01

Usually i prefer like below in swift 3, because i can add file name and create a file easily

通常我更喜欢在swift 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)
    }
}