How to read from a plist with Swift 3 iOS app

38,913

Solution 1

Same way you have done in Swift 2.3 or lower just syntax is changed.

if let path = Bundle.main.path(forResource: "fileName", ofType: "plist") {

    //If your plist contain root as Array
    if let array = NSArray(contentsOfFile: path) as? [[String: Any]] {

    }

    ////If your plist contain root as Dictionary
    if let dic = NSDictionary(contentsOfFile: path) as? [String: Any] {

    }
}

Note: In Swift it is better to use Swift's generic type Array and Dictionary instead of NSArray and NSDictionary.

Edit: Instead of NSArray(contentsOfFile: path) and NSDictionary(contentsOfFile:) we can also use PropertyListSerialization.propertyList(from:) to read data from plist file.

if let fileUrl = Bundle.main.url(forResource: "fileName", withExtension: "plist"),
   let data = try? Data(contentsOf: fileUrl) {
       if let result = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [[String: Any]] { // [String: Any] which ever it is 
            print(result)
       }
}

Solution 2

As Swift 4 introduces Codable

Step 1: Load the Plist File from bundle.

Step 2: Use PropertyListDecoder for the decoding of property list values into semantic Decodable types.

Step 3: Create Codable Struct

Complete code -

 func setData() {
        // location of plist file
        if let settingsURL = Bundle.main.path(forResource: "JsonPlist", ofType: "plist") {

            do {
                var settings: MySettings?
                let data = try Data(contentsOf: URL(fileURLWithPath: settingsURL))
                    let decoder = PropertyListDecoder()
                settings = try decoder.decode(MySettings.self, from: data)
                    print("toolString is \(settings?.toolString ?? "")")
                print("DeviceDictionary is \(settings?.deviceDictionary?.phone ?? "")")
                print("RootPartArray is \(settings?.RootPartArray ?? [""])")

            } catch {
                print(error)
            }
        }
    }
}
struct MySettings: Codable {
    var toolString: String?
    var deviceDictionary: DeviceDictionary?
    var RootPartArray: [String]?

    private enum CodingKeys: String, CodingKey {
        case toolString = "ToolString"
        case deviceDictionary = "DeviceDictionary"
        case RootPartArray
    }

    struct DeviceDictionary: Codable {
        var phone: String?
        init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            phone = try values.decodeIfPresent(String.self, forKey: .phone)
        }
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        toolString = try values.decodeIfPresent(String.self, forKey: .toolString)
        deviceDictionary = try values.decodeIfPresent(DeviceDictionary.self, forKey: .deviceDictionary)
        RootPartArray = try values.decodeIfPresent([String].self, forKey: .RootPartArray)

    }
}

Sample Plist file -> https://gist.github.com/janeshsutharios/4b0fb0e3edeff961d3e1f2829eb518db

Solution 3

Here is a Swift 3 implementation, based on Nirav D's answer:

    /// Read Plist File.
    ///
    /// - Parameter fileURL: file URL.
    /// - Returns: return plist content.
    func ReadPlist(_ fileURL: URL) -> [String: Any]? {
        guard fileURL.pathExtension == FileExtension.plist, let data = try? Data(contentsOf: fileURL) else {
            return nil
        }
        guard let result = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [String: Any] else {
            return nil
        }
        print(result)
        return result
    }

Solution 4

Here is example how to get BundleID from Info plist:

var appBundleID = "Unknown Bundle ID"    
if let bundleDict = Bundle.main.infoDictionary, 
   let bundleID = bundleDict[kCFBundleIdentifierKey as String] as? String {
       appBundleID = bundleID
   }

The same way you may easily access any key. This approach is good for many-target projects.

Share:
38,913
E_Ri
Author by

E_Ri

I make stuff.

Updated on March 12, 2020

Comments

  • E_Ri
    E_Ri about 4 years

    -Disclaimer-
    I'm extremely new to iOS and Swift development, but I'm not particularly new to programming.

    I have a basic iOS application with Swift3 elements in it.
    I've created a plist file with some entries I want to read and display in my application. (No write access is necessary)

    How can you read a value for a given key for a bundled plist file, in Swift3?

    This seems like a really simple question to me, but a bunch of searching is making me question my whole conceptual approach.

    Helpful tips would be appreciated.