How to Read Plist without using NSDictionary in Swift?

The native Swift way is to use PropertyListSerialization

if let url = Bundle.main.url(forResource:"Config", withExtension: "plist") {
   do {
     let data = try Data(contentsOf:url)
     let swiftDictionary = try PropertyListSerialization.propertyList(from: data, format: nil) as! [String:Any]
      // do something with the dictionary
   } catch {
      print(error)
   }
}

You can also use NSDictionary(contentsOf: with a type cast:

if let url = Bundle.main.url(forResource:"Config", withExtension: "plist"),
   let myDict = NSDictionary(contentsOf: url) as? [String:Any] {
   print(myDict)
}

but you explicitly wrote: without using NSDictionary(contentsOf...

Basically don't use NSDictionary without casting in Swift, you are throwing away the important type information.


PropertyListDecoder can be used to decode plist file directly to Objects.

1: Sample Plist File (sample.plist)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>key1</key>
    <string>valua for key1</string>
    <key> key2</key>
    <string>valua for key1</string>
    <key>CustomClass1</key>
    <dict>
        <key>customClass1_key</key>
        <string>customClass1_value</string>
    </dict>
    <key>CustomClass2</key>
    <dict>
        <key>customClass2_kek</key>
        <string>customClasse_value</string>
    </dict>
</dict>
</plist>

2: Corespoinding Models for plist

struct PlistConfiguration:Codable {
    var key1:String?
    var customClass1Obj: CustomClass1?
    var customClass2Obj: CustomClass2?
    
    private enum CodingKeys : String, CodingKey {
              case key1 = "key1"
              case customClass1Obj = "CustomClass1"
              case customClass2Obj = "CustomClass2"
    }
    
}

2.1: Nested Model

struct CustomClass1:Codable {
    var customClass1_key:String?
    private enum CodingKeys : String, CodingKey {
              case customClass1_key = "customClass1_key"
    }
    
}

2.2: Nested Model

struct CustomClass2:Codable {
    var customClass2_key:String?
    private enum CodingKeys : String, CodingKey {
              case customClass2_key = "customClass2_key"
    }
    
}

3: Read Plist from main app bundle

func parseConfig() -> PlistConfiguration {
        let url = Bundle.main.url(forResource: "sample", withExtension: "plist")!
        let data = try! Data(contentsOf: url)
        let decoder = PropertyListDecoder()
        return try! decoder.decode(PlistConfiguration.self, from: data)
    }