Search code examples
swiftplistnsfilemanagernsbundlexcode6.4

reading from .plist always returns nil


All of my attempts to read from a plist have resulted in a nil value returned, I've tried this in several ways on both Xcode 6 & Xcode beta 7. Also, there are quite a few similar questions on stack, I've tried many of them, but none of them resolve this issue.

I've added my words.plist by clicking on:

{my project} > targets > build phases > copy Bundle Resources

enter image description here

Then I tried several variations of the following code in my ViewController:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
    let documentsDirectory = paths[0] as! String
    let path = documentsDirectory.stringByAppendingPathComponent("words.plist")

    let fileManager = NSFileManager.defaultManager()

    //check if file exists
    if(!fileManager.fileExistsAtPath(path)) {
        // If it doesn't, copy it from the default file in the Bundle
        if let bundlePath = NSBundle.mainBundle().pathForResource("words", ofType: "plist") {

            let resultDictionary = NSMutableDictionary(contentsOfFile: bundlePath)
            println("Bundle words file is --> \(resultDictionary?.description)") // this is nil!!!

            fileManager.copyItemAtPath(bundlePath, toPath: path, error: nil)

        } else {
            println("words not found. Please, make sure it is part of the bundle.")
        }
    } else {
        println("words already exits at path.")
        // use this to delete file from documents directory
        //fileManager.removeItemAtPath(path, error: nil)

    }
    print("entering if-let")
    if let pfr = NSBundle.mainBundle().pathForResource("words", ofType: "plist") {
        print("\nin let\n")
        print(pfr)
        print("\nentering dict if-let\n")
        if let dict = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
            // use swift dictionary as normal
            print("\nin let\n")
            print(dict)
        }   
    }
}

enter image description here

Question

Why am I getting a nil value and whats the proper way to add a plist file and read from it?


update:

inside my if statement the following is nil:

let resultDictionary = NSMutableDictionary(contentsOfFile: bundlePath)
println("Bundle words file is --> \(resultDictionary?.description)") // this is nil!!!

To me, this would indicate that either Xcode doesn't know about my words.plist file, or that I'm pointing my bundlePath to the wrong location.


Solution

  • the issue:

    As @Steven Fisher stated, in the comments. My .plist file was an Array and not an NSDictionary. So I just had to switch two lines from my code:

    let resultDictionary = NSMutableDictionary(contentsOfFile: bundlePath)
    

    to

    let resultDictionary = NSMutableArray(contentsOfFile: bundlePath)
    

    and also

    if let dict = NSDictionary(contentsOfFile: path) { //...
    

    to

    if let dict = NSArray(contentsOfFile: path) { //..
    

    final working code:

    override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
            let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
            let documentsDirectory = paths[0] as! String
            let path = documentsDirectory.stringByAppendingPathComponent("words.plist")
    
            let fileManager = NSFileManager.defaultManager()
    
            //check if file exists
            if(!fileManager.fileExistsAtPath(path)) {
                // If it doesn't, copy it from the default file in the Bundle
                if let bundlePath = NSBundle.mainBundle().pathForResource("words", ofType: "plist") {
    
                    let resultDictionary = NSMutableArray(contentsOfFile: bundlePath)
                    println("Bundle words file is --> \(resultDictionary?.description)")
    
                    fileManager.copyItemAtPath(bundlePath, toPath: path, error: nil)
    
                } else {
                    println("words not found. Please, make sure it is part of the bundle.")
                }
            } else {
                println("words already exits at path.")
                // use this to delete file from documents directory
                //fileManager.removeItemAtPath(path, error: nil)
    
            }
            print("entering if-let")
            if let pfr = NSBundle.mainBundle().pathForResource("words", ofType: "plist") {
                print("\nin let\n")
                print(pfr)
                print("\nentering dict if-let\n")
                if let dict = NSArray(contentsOfFile: pfr) {
                    // use swift dictionary as normal
                    print("\nin let\n")
                    print(dict)
                }
    
            }
        }