स्विफ्ट में NSDocumentDirectory कैसे खोजें?


162

मैं कोड के साथ दस्तावेज़ फ़ोल्डर में जाने की कोशिश कर रहा हूँ:

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

लेकिन Xcode त्रुटि देता है: Cannot convert expression's type 'AnyObject[]!' to type 'NSSearchPathDirectory'

मैं समझने की कोशिश कर रहा हूं कि कोड में क्या गलत है।


1
इस सवाल के कई संपादन थे जो संभावित समाधान जोड़ रहे थे। सारी बात गड़बड़ थी। मैंने स्पष्टता के लिए पहले संस्करण में वापस रोल किया है। उत्तर प्रश्न में नहीं हैं और उन्हें उत्तर के रूप में पोस्ट किया जाना चाहिए। मैं चर्चा के लिए उपलब्ध हूं कि क्या कोई सोचता है कि मेरा रोलबैक बहुत कट्टरपंथी है। धन्यवाद।
एरिक आया

जवाबों:


256

जाहिर है, संकलक NSSearchPathDirectory:0एक सरणी है, और निश्चित रूप से यह NSSearchPathDirectoryइसके बजाय प्रकार की उम्मीद करता है । निश्चित रूप से एक सहायक त्रुटि संदेश नहीं।

लेकिन कारणों के रूप में:

पहले, आप तर्क नामों और प्रकारों को भ्रमित कर रहे हैं। फ़ंक्शन परिभाषा पर एक नज़र डालें:

func NSSearchPathForDirectoriesInDomains(
    directory: NSSearchPathDirectory,
    domainMask: NSSearchPathDomainMask,
    expandTilde: Bool) -> AnyObject[]!
  • directoryऔर domainMaskनाम हैं, आप प्रकारों का उपयोग कर रहे हैं, लेकिन आपको उन्हें कार्यों के लिए वैसे भी छोड़ देना चाहिए। उनका उपयोग मुख्य रूप से विधियों में किया जाता है।
  • इसके अलावा, स्विफ्ट दृढ़ता से टाइप किया गया है, इसलिए आपको केवल 0. का उपयोग नहीं करना चाहिए। इसके बजाय एनम के मान का उपयोग करें।
  • और अंत में, यह केवल एक पथ नहीं, बल्कि एक सरणी देता है।

ताकि हमें छोड़ दिया जाए (स्विफ्ट 2.0 के लिए अद्यतन):

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

और स्विफ्ट 3 के लिए:

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

यह जवाब Xcode 6.0 में विफल रहा। कलाकारों के NSStringबजाय होना चाहिए String
डैनियल टी।

1
@DanielT। बस फिर से कोशिश की और StringXcode 6.0 और 6.1 में काम करता है। आम तौर पर, Stringऔर NSStringस्विफ्ट में स्वचालित रूप से पाले जाते हैं। हो सकता है कि आपको NSStringकिसी अन्य कारण से कास्ट करना पड़े ।
nschum

क्या आपने इसे खेल के मैदान या वास्तविक ऐप में आज़माया था? परिणाम अलग हैं। कोड Stringएक खेल के मैदान में खेलता है , लेकिन एक ऐप में नहीं। प्रश्न (की जाँच करें stackoverflow.com/questions/26450003/... )
डैनियल टी

दोनों, वास्तव में। स्विफ्ट में एक सूक्ष्म बग हो सकता है, मुझे लगता है ... मैं सिर्फ सुरक्षित होने के उत्तर को संपादित करूंगा। :) धन्यवाद
nschum

3
फिर से ऐप चलाने से एक अलग राह बनती है, क्यों ?: (1) /var/mobile/Containers/Data/Application/9E18A573-6429-434D-9B42-08642B643970/Documents(2)/var/mobile/Containers/Data/Application/77C8EA95-B77A-474D-8522-1F24F854A291/Documents
जानोस

40

स्विफ्ट 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
}

32

NSString आधारित पथों के बजाय फ़ाइलों और निर्देशिकाओं के लिए NSURL का उपयोग करने के लिए आधुनिक अनुशंसा है:

यहां छवि विवरण दर्ज करें

तो 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 को वापस करने के लिए फ़ाइल URL और एक अधिक आधुनिक एपीआई का उपयोग करता है, बंडल के प्रारंभिक संस्करण की प्रतिलिपि बनाता है यदि यह पहले से मौजूद नहीं है, या त्रुटि के मामले में शून्य है।


24

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 • स्विफ्ट 2.1

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

21

आमतौर पर मैं इस एक्सटेंशन का उपयोग करना पसंद करता हूं:

स्विफ्ट 3.x और स्विफ्ट 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]
    }
}

इसे कहाँ पर कॉल करें?
बी। श्रवण कुमार

आपके द्वारा आवश्यक कोड के प्रत्येक भाग के लिए: let path = FileManager.documentsDir()+("/"+"\(fileName)")आप इसे थ्रेड (मुख्य या पृष्ठभूमि) के बीच अंतर के बिना कह सकते हैं।
एलेसांद्रो ओरनानो

14

हर कोई जो उदाहरण के लिए दिखता है जो स्विफ्ट 2.2 के साथ काम करता है, आधुनिक के साथ अबिज़र्न कोड त्रुटि को पकड़ने की कोशिश करता है

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
}

अपडेट मैंने याद किया है कि नई स्विफ्ट 2.0 में गार्ड (रूबी जब तक एनालॉग) नहीं है, इसलिए गार्ड के साथ यह बहुत छोटा और अधिक पठनीय है

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

अधिक सुविधाजनक स्विफ्ट 3 विधि:

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

1
या यहां तक ​​किFileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
Iulian Onofrei

7
मुझे नहीं लगता कि जब भी हम दस्तावेज़ निर्देशिका के लिए URL प्राप्त करना चाहते हैं, तो हर बार एक नए फ़ाइल प्रबंधक को इंस्टेंट करना आवश्यक है।
एंड्री गोर्डीव

1
मुझे लगा कि यह वही बात है। धन्यवाद!
इयूलियन ओनोफ्रेई

5

Xcode 8b4 स्विफ्ट 3.0

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

3

आमतौर पर मैं स्विफ्ट 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)
    }
}

1
absoluteStringगलत है। फ़ाइल पथ को प्राप्त करने के लिए एक fileurL प्राप्त करें, जिसे आपको अपनी .pathसंपत्ति प्राप्त करने की आवश्यकता है
Leo Dabus
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.