Swift'te NSDocumentDirectory nasıl bulunur?


162

Kod ile Belgeler klasörüne yol almaya çalışıyorum:

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

ancak Xcode hata veriyor: Cannot convert expression's type 'AnyObject[]!' to type 'NSSearchPathDirectory'

Kodda neyin yanlış olduğunu anlamaya çalışıyorum.


1
Bu soruda olası çözümler ekleyen birkaç düzenleme yapıldı. Her şey bir karışıklıktı. Netlik için ilk sürüme geri döndüm. Cevaplar bir soruya ait değildir ve cevap olarak gönderilmelidir. Birinin geri alma işlemimin çok radikal olduğunu düşünüp düşünmediğini tartışmaya hazırım. Teşekkürler.
Eric Aya

Yanıtlar:


256

Görünüşe göre, derleyici NSSearchPathDirectory:0bir dizi olduğunu düşünüyor ve elbette bunun NSSearchPathDirectoryyerine türü bekliyor . Kesinlikle yararlı bir hata mesajı değil.

Ancak nedenlere gelince:

İlk olarak, argüman adlarını ve türlerini karıştırıyorsunuz. İşlev tanımına bir göz atın:

func NSSearchPathForDirectoriesInDomains(
    directory: NSSearchPathDirectory,
    domainMask: NSSearchPathDomainMask,
    expandTilde: Bool) -> AnyObject[]!
  • directoryve domainMaskisimler, türleri kullanıyorsunuz, ancak bunları yine de işlevler için dışarıda bırakmalısınız. Öncelikle yöntemlerde kullanılırlar.
  • Ayrıca, Swift güçlü bir şekilde yazılmıştır, bu yüzden sadece 0 kullanmamalısınız. Bunun yerine numaralandırmanın değerini kullanın.
  • Ve son olarak, sadece tek bir yol değil, bir dizi döndürür.

Böylece bizi bırakır (Swift 2.0 için güncellendi):

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

ve Swift 3 için:

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

Bu yanıt Xcode 6.0'da başarısız oldu. Oyuncular NSStringdeğil String.
Daniel T.

1
@DanielT. Sadece tekrar denedim ve StringXcode 6.0 ve 6.1'de çalışıyor. Genellikle Stringve NSStringSwift'te otomatik olarak köprülenir. Belki NSStringbaţka bir nedenden ötürü kullanman gerekti.
nschum

Bir oyun alanında veya gerçek bir uygulamada denediniz mi? Sonuçlar farklı. Kod Stringbir oyun alanında bir atılır, ancak bir uygulamada değil. Soruyu kontrol et ( stackoverflow.com/questions/26450003/… )
Daniel T.

Aslında ikisi de. Swift'te ince bir hata olabilir, sanırım ... Cevabı güvenli olacak şekilde düzenleyeceğim. :) Teşekkürler
nschum

3
uygulamayı tekrar çalıştırmak farklı bir yol oluşturur, neden ?: (1) /var/mobile/Containers/Data/Application/9E18A573-6429-434D-9B42-08642B643970/Documents(2)/var/mobile/Containers/Data/Application/77C8EA95-B77A-474D-8522-1F24F854A291/Documents
János

40

Swift 3.0 ve 4.0

Bir diziden doğrudan ilk öğenin alınması, yolun bulunmaması durumunda istisnaya neden olabilir. Bu yüzden aramak firstve açmak daha iyi bir çözümdür

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
}

32

Modern öneri NSURL'leri NSString tabanlı yollar yerine dosya ve dizinler için kullanmaktır:

resim açıklamasını buraya girin

Uygulamanın bir NSURL olarak Belge dizinini almak için:

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
}

Bu, ilk olarak hata işlemeye sahiptir, çünkü bu tür durumlarda uygulamanızın ne yapacağına bağlıdır. Ancak bu, veritabanı URL'sini döndürmek için dosya URL'lerini ve daha modern bir API'yi kullanır, henüz yoksa ilk sürümü paketten kopyalar veya hata durumunda sıfırdır.


24

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 • Hızlı 2.1

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

21

Genellikle bu uzantıyı kullanmayı tercih ederim:

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

bunu nereden çağırmalı?
B.Saravana Kumar

Kodunuzun ihtiyacınız olan her parçası için:, let path = FileManager.documentsDir()+("/"+"\(fileName)")iş parçacığı (ana veya arka plan) arasında fark olmadan arayabilirsiniz.
Alessandro Ornano

14

Swift 2.2 ile çalışan örnek görünen herkes için, modern ile Abizern kodu hata yakalamayı deneyin

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
}

Güncelleme Yeni hızlı 2.0'ın koruyucusu olduğunu (analog olmadığı sürece Ruby) kaçırdım, bu yüzden koruyucuyla çok daha kısa ve daha okunabilir

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 
}

13

Daha kullanışlı Swift 3 yöntemi:

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

1
Ya daFileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
Iulian Onofrei

7
Belgeler dizini için her URL almak istediğimizde yeni bir dosya yöneticisi başlatmanın gerekli olduğunu düşünmüyorum.
Andrey Gordeev

1
Aynı şey olduğunu düşündüm. Teşekkürler!
Iulian Onofrei

5

Xcode 8b4 Swift 3.0

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

3

Genellikle hızlı 3'te aşağıdaki gibi tercih ederim , çünkü dosya adı ekleyebilir ve kolayca bir dosya oluşturabilirim

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

1
absoluteStringHata. Bir dosyaURL dosya yolunu almak için onun .pathözelliğini almanız gerekir
Leo Dabus
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.