¿Cómo obtengo un plist como diccionario en Swift?

197

Estoy jugando con el nuevo lenguaje de programación Swift de Apple y tengo algunos problemas ...

Actualmente estoy tratando de leer un archivo plist, en Objective-C haría lo siguiente para obtener el contenido como NSDictionary:

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Config" ofType:@"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:filePath];

¿Cómo obtengo un plist como diccionario en Swift?

Supongo que puedo obtener el camino hacia la lista con:

let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist")

Cuando esto funciona (¿es correcto?): ¿Cómo obtengo el contenido como un diccionario?

También una pregunta más general:

¿Está bien usar las clases NS * predeterminadas ? Creo que sí ... ¿o me estoy perdiendo algo? Hasta donde yo sé, ¿las clases NS * de marco predeterminadas siguen siendo válidas y se pueden usar?

Sebastian
fuente
La respuesta ya no es válida, ¿podría seleccionar la respuesta de Ashok?
RodolfoAntonici

Respuestas:

51

En Swift 3.0 Lectura de Plist.

func readPropertyList() {
        var propertyListFormat =  PropertyListSerialization.PropertyListFormat.xml //Format of the Property List.
        var plistData: [String: AnyObject] = [:] //Our data
        let plistPath: String? = Bundle.main.path(forResource: "data", ofType: "plist")! //the path of the data
        let plistXML = FileManager.default.contents(atPath: plistPath!)!
        do {//convert the data to a dictionary and handle errors.
            plistData = try PropertyListSerialization.propertyList(from: plistXML, options: .mutableContainersAndLeaves, format: &propertyListFormat) as! [String:AnyObject]

        } catch {
            print("Error reading plist: \(error), format: \(propertyListFormat)")
        }
    }

Leer más CÓMO UTILIZAR LISTAS DE PROPIEDADES (.PLIST) EN SWIFT .

Ashok R
fuente
Askok ¡Perdí muchas horas tratando de encontrar una respuesta a esto hoy con esto! ¡¡GRACIAS!! Esto funcionó perfectamente !!!
user3069232
281

Todavía puede usar NSDictionaries en Swift:

Para Swift 4

 var nsDictionary: NSDictionary?
 if let path = Bundle.main.path(forResource: "Config", ofType: "plist") {
    nsDictionary = NSDictionary(contentsOfFile: path)
 }

Para Swift 3+

if let path = Bundle.main.path(forResource: "Config", ofType: "plist"),
   let myDict = NSDictionary(contentsOfFile: path){
    // Use your myDict here
}

Y versiones anteriores de Swift

var myDict: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist") {
    myDict = NSDictionary(contentsOfFile: path)
}
if let dict = myDict {
    // Use your dict here
}

Las NSClasses todavía están disponibles y son perfectas para usar en Swift. Creo que probablemente querrán cambiar el enfoque a rápido pronto, pero actualmente las API rápidas no tienen toda la funcionalidad de las NSClasses principales.

Connor
fuente
hmm cuando intento usar el código que me proporcionaste, aparece el error: xxx no tiene un miembro llamado dict
KennyVB
Funciona bien en el patio de recreo aunque. simplemente no en mi documento rápido
KennyVB
¿Cómo se ve si Array?
Arnlee Vizcayno
Parece que mainBundle()es solo mainen Swift 3
BallpointBen
8
Esta respuesta está desactualizada. Incluso en Swift 3 no debe usar NSArray/NSDictionarypara leer datos de la lista de propiedades. PropertyListSerialization(y en Swift 4, alternativamente, el Codableprotocolo) es la API apropiada. Proporciona un manejo moderno de errores y los datos se pueden convertir directamente a tipos de colección nativos de Swift.
vadian
141

Esto es lo que hago si quiero convertir un .plist a un diccionario Swift:

if let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist") {
  if let dict = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
    // use swift dictionary as normal
  }
}

Editado para Swift 2.0:

if let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist"), dict = NSDictionary(contentsOfFile: path) as? [String: AnyObject] {
    // use swift dictionary as normal
}

Editado para Swift 3.0:

if let path = Bundle.main.path(forResource: "Config", ofType: "plist"), let dict = NSDictionary(contentsOfFile: path) as? [String: AnyObject] {
        // use swift dictionary as normal
}
pheedsta
fuente
3
Creo que esta es la respuesta "más correcta" del grupo hasta que haya una forma nativa y rápida de hacer esto.
DudeOnRock
1
Esta respuesta está desactualizada. En Swift 3 no debe usar NSArray/NSDictionarypara leer datos de la lista de propiedades. PropertyListSerialization(y en Swift 4, alternativamente, el Codableprotocolo) es la API apropiada. Proporciona un manejo moderno de errores y los datos se pueden convertir directamente a tipos de colección nativos de Swift.
vadian
47

Swift 4.0

Ahora puede usar el protocolo Decodable para decodificar un .plist en una estructura personalizada. Revisaré un ejemplo básico, para estructuras .plist más complicadas, recomiendo leer en Decodable / Encodable (un buen recurso está aquí: https://benscheirman.com/2017/06/swift-json/ ).

Primero configure su estructura en el formato de su archivo .plist. Para este ejemplo, consideraré un .plist con un Diccionario de nivel raíz y 3 entradas: 1 Cadena con la clave "nombre", 1 Int con la clave "age" y 1 Boolean con la clave "single". Aquí está la estructura:

struct Config: Decodable {
    private enum CodingKeys: String, CodingKey {
        case name, age, single
    }

    let name: String
    let age: Int
    let single: Bool
}

Suficientemente simple. Ahora la parte genial. Usando la clase PropertyListDecoder podemos analizar fácilmente el archivo .plist en una instanciación de esta estructura:

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

No hay mucho más código de qué preocuparse, y todo está en Swift. Mejor aún, ahora tenemos una instanciación de la estructura de configuración que podemos usar fácilmente:

let config = parseConfig()
print(config.name) 
print(config.age)
print(config.single) 

Esto imprime el valor de las teclas "nombre", "edad" y "simple" en la lista.

ekreloff
fuente
1
Esa es la mejor respuesta para Swift 4. Pero ¿por qué no Bundle.main.url(forResource: "Config", withExtension: "plist")y deshacerse de él URL(fileURLWithPath? Y como se requiere que el archivo exista (en tiempo de diseño / compilación), todos los valores se pueden desenvolver a la fuerza. El código no debe bloquearse si todo está diseñado correctamente.
vadiano
@vadian Claro que puedes usar url(forResource: "Config", withExtension: "plist"), solo estaba haciendo coincidir lo que hizo el OP en su código como punto de comparación. En cuanto a la fuerza para desenvolver todo, trato de errar por el lado de la precaución. Creo que esa es una pregunta fundamental para Swift en general. Prefiero saber exactamente qué hará mi código en cualquier situación que el bloqueo.
ekreloff
1) No adoptes malos hábitos si hay una API más apropiada. 2) Ese es uno de los pocos casos donde un choque forzado descubre un error de diseño. Se requiere que cualquier archivo en el paquete esté presente en el momento de la compilación y no se puede cambiar en tiempo de ejecución porque todos los archivos están firmados con código. Una vez más: el código no debe bloquearse si todo está diseñado correctamente .
vadiano
Sí, sabes tu derecho. No me di cuenta de que ese era el caso con los recursos de Bundle.
ekreloff
2
@NaveenGeorgeThoppan si usa este ejemplo como su diccionario, entonces simplemente sería decoder.decode([Config].self, from: data). (Observe los corchetes alrededor de [Config])
ekreloff
22

Esta respuesta usa objetos nativos Swift en lugar de NSDictionary.

Swift 3.0

//get the path of the plist file
guard let plistPath = Bundle.main.path(forResource: "level1", ofType: "plist") else { return }
//load the plist as data in memory
guard let plistData = FileManager.default.contents(atPath: plistPath) else { return }
//use the format of a property list (xml)
var format = PropertyListSerialization.PropertyListFormat.xml
//convert the plist data to a Swift Dictionary
guard let  plistDict = try! PropertyListSerialization.propertyList(from: plistData, options: .mutableContainersAndLeaves, format: &format) as? [String : AnyObject] else { return }
//access the values in the dictionary 
if let value = plistDict["aKey"] as? String {
  //do something with your value
  print(value)
}
//you can also use the coalesce operator to handle possible nil values
var myValue = plistDict["aKey"] ?? ""
Tommie C.
fuente
¿Hay una versión concisa de esto?
harsh_v
18

He estado trabajando con Swift 3.0 y quería aportar una respuesta para la sintaxis actualizada. Además, y posiblemente lo más importante, estoy usando el objeto PropertyListSerialization para hacer el trabajo pesado, que es mucho más flexible que simplemente usar NSDictionary, ya que permite una matriz como el tipo raíz del plist.

A continuación se muestra una captura de pantalla de la lista que estoy usando. Es un poco complicado, para mostrar la potencia disponible, pero esto funcionará para cualquier combinación permitida de tipos de plist.

Archivo plist de muestra Como puede ver, estoy usando una matriz de String: diccionarios de cadenas para almacenar una lista de nombres de sitios web y su URL correspondiente.

Estoy usando el objeto PropertyListSerialization , como se mencionó anteriormente, para hacer el trabajo pesado por mí. Además, Swift 3.0 se ha vuelto más "Swifty", por lo que todos los nombres de objetos han perdido el prefijo "NS".

let path = Bundle.main().pathForResource("DefaultSiteList", ofType: "plist")!
let url = URL(fileURLWithPath: path)
let data = try! Data(contentsOf: url)
let plist = try! PropertyListSerialization.propertyList(from: data, options: .mutableContainers, format: nil)

Después de que el código anterior se ejecute plistserá de tipo Array<AnyObject>, pero sabemos de qué tipo es realmente, por lo que podemos convertirlo en el tipo correcto:

let dictArray = plist as! [[String:String]]
// [[String:String]] is equivalent to Array< Dictionary<String, String> >

Y ahora podemos acceder a las diversas propiedades de nuestro Array of String: String Dictionaries de forma natural. Esperemos convertirlos en estructuras o clases reales fuertemente tipadas;)

print(dictArray[0]["Name"])
Mella
fuente
8

Es mejor usar diccionarios y matrices nativos porque han sido optimizados para su uso con Swift. Dicho esto, puedes usar NS ... clases rápidamente y creo que esta situación lo garantiza. Así es como lo implementaría:

var path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist")
var dict = NSDictionary(contentsOfFile: path)

Hasta ahora (en mi opinión), esta es la forma más fácil y eficiente de acceder a un plist, pero en el futuro espero que Apple agregue más funcionalidades (como usar plist) en los diccionarios nativos.

67 cerezas
fuente
Hasta donde usted sabe, ¿ya ha agregado la lectura simple a los diccionarios nativos?
SpacyRicochet
8

Swift - Leer / Escribir plist y archivo de texto ...

override func viewDidLoad() {
    super.viewDidLoad()

    let fileManager = (NSFileManager .defaultManager())
    let directorys : [String]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory,NSSearchPathDomainMask.AllDomainsMask, true) as? [String]

    if (directorys != nil){
        let directories:[String] = directorys!;
        let dictionary = directories[0]; //documents directory


        //  Create and insert the data into the Plist file  ....
        let plistfile = "myPlist.plist"
        var myDictionary: NSMutableDictionary = ["Content": "This is a sample Plist file ........."]
        let plistpath = dictionary.stringByAppendingPathComponent(plistfile);

        if !fileManager .fileExistsAtPath(plistpath){//writing Plist file
            myDictionary.writeToFile(plistpath, atomically: false)
        }
        else{            //Reading Plist file
            println("Plist file found")

            let resultDictionary = NSMutableDictionary(contentsOfFile: plistpath)
            println(resultDictionary?.description)
        }


        //  Create and insert the data into the Text file  ....
        let textfile = "myText.txt"
        let sampleText = "This is a sample text file ......... "

        let textpath = dictionary.stringByAppendingPathComponent(textfile);
        if !fileManager .fileExistsAtPath(textpath){//writing text file
            sampleText.writeToFile(textpath, atomically: false, encoding: NSUTF8StringEncoding, error: nil);
        } else{
            //Reading text file
            let reulttext  = String(contentsOfFile: textpath, encoding: NSUTF8StringEncoding, error: nil)
            println(reulttext)
        }
    }
    else {
        println("directory is empty")
    }
}
Nithin Sathyan
fuente
8

Swift 2.0: Acceso a la lista de información

Tengo un diccionario llamado CoachMarksDictionary con un valor booleano en Info.Plist. Quiero acceder al valor bool y hacerlo realidad.

let path = NSBundle.mainBundle().pathForResource("Info", ofType: "plist")!
  let dict = NSDictionary(contentsOfFile: path) as! [String: AnyObject]

  if let CoachMarksDict = dict["CoachMarksDictionary"] {
       print("Info.plist : \(CoachMarksDict)")

   var dashC = CoachMarksDict["DashBoardCompleted"] as! Bool
    print("DashBoardCompleted state :\(dashC) ")
  }

Escribiendo a Plist:

Desde una lista personalizada: - (Crear desde File-New-File-Resource-PropertyList. Se agregaron tres cadenas denominadas: DashBoard_New, DashBoard_Draft, DashBoard_Completed)

func writeToCoachMarksPlist(status:String?,keyName:String?)
 {
  let path1 = NSBundle.mainBundle().pathForResource("CoachMarks", ofType: "plist")
  let coachMarksDICT = NSMutableDictionary(contentsOfFile: path1!)! as NSMutableDictionary
  var coachMarksMine = coachMarksDICT.objectForKey(keyName!)

  coachMarksMine  = status
  coachMarksDICT.setValue(status, forKey: keyName!)
  coachMarksDICT.writeToFile(path1!, atomically: true)
 }

El método se puede llamar como

self.writeToCoachMarksPlist(" true - means user has checked the marks",keyName: "the key in the CoachMarks dictionary").
AG
fuente
¡Esto es lo que estaba buscando! ¡Gracias amigo!
Jayprakash Dubey
6

Convertido en una extensión de conveniencia a través de la respuesta de Nick:

extension Dictionary {
    static func contentsOf(path: URL) -> Dictionary<String, AnyObject> {
        let data = try! Data(contentsOf: path)
        let plist = try! PropertyListSerialization.propertyList(from: data, options: .mutableContainers, format: nil)

        return plist as! [String: AnyObject]
    }
}

uso:

let path = Bundle.main.path(forResource: "plistName", ofType: "plist")!
let url = URL(fileURLWithPath: path)
let dict = Dictionary<String, AnyObject>.contentsOf(path: url)

Estaría dispuesto a apostar que también funcionaría para crear una extensión similar para las matrices

mredig
fuente
5

realmente puede hacerlo en 1 línea

    var dict = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("Config", ofType: "plist"))
KennyVB
fuente
5

Puede leer plist en SWIFT Language de esta manera:

let path = NSBundle.mainBundle().pathForResource("PriceList", ofType: "plist")
let dict = NSDictionary(contentsOfFile: path)

Leer el valor del diccionario único:

let test: AnyObject = dict.objectForKey("index1")

Si desea obtener un diccionario multidimensional completo en plist:

let value: AnyObject = dict.objectForKey("index2").objectForKey("date")

Aquí está el plist:

<plist version="1.0">
<dict>
<key>index2</key>
<dict>
    <key>date</key>
    <string>20140610</string>
    <key>amount</key>
    <string>110</string>
</dict>
<key>index1</key>
<dict>
    <key>amount</key>
    <string>125</string>
    <key>date</key>
    <string>20140212</string>
</dict>
</dict>
</plist>
imti
fuente
5

Dado que esta respuesta no está aquí todavía, sólo quería señalar también se puede utilizar la propiedad infoDictionary para obtener la información plist como un diccionario, Bundle.main.infoDictionary.

Aunque algo así Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) puede ser más rápido si solo está interesado en un elemento específico en la lista de información.

// Swift 4

// Getting info plist as a dictionary
let dictionary = Bundle.main.infoDictionary

// Getting the app display name from the info plist
Bundle.main.infoDictionary?[kCFBundleNameKey as String]

// Getting the app display name from the info plist (another way)
Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String)
Scott Marchant
fuente
3

en mi caso creo una NSDictionaryllamada appSettingsy agrego todas las claves necesarias. Para este caso, la solución es:

if let dict = NSBundle.mainBundle().objectForInfoDictionaryKey("appSettings") {
  if let configAppToken = dict["myKeyInsideAppSettings"] as? String {

  }
}
jose920405
fuente
Gracias. objectForInfoDictionaryKeyera exactamente lo que estaba buscando.
LunaCodeGirl
2

Puede usar eso, creo una extensión simple para Dictionary en github https://github.com/DaRkD0G/LoadExtension

extension Dictionary {
    /**
        Load a Plist file from the app bundle into a new dictionary

        :param: File name
        :return: Dictionary<String, AnyObject>?
    */
    static func loadPlistFromProject(filename: String) -> Dictionary<String, AnyObject>? {

        if let path = NSBundle.mainBundle().pathForResource("GameParam", ofType: "plist") {
            return NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject>
        }
        println("Could not find file: \(filename)")
        return nil
    }
}

Y puedes usar eso para cargar

/**
  Example function for load Files Plist

  :param: Name File Plist
*/
func loadPlist(filename: String) -> ExampleClass? {
    if let dictionary = Dictionary<String, AnyObject>.loadPlistFromProject(filename) {
        let stringValue = (dictionary["name"] as NSString)
        let intergerValue = (dictionary["score"] as NSString).integerValue
        let doubleValue = (dictionary["transition"] as NSString).doubleValue

        return ExampleClass(stringValue: stringValue, intergerValue: intergerValue, doubleValue: doubleValue)
    }
    return nil
}
YannSteph
fuente
2

Aquí hay una versión un poco más corta, basada en la respuesta de @connor

guard let path = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist"),
    let myDict = NSDictionary(contentsOfFile: path) else {
    return nil
}

let value = dict.value(forKey: "CLIENT_ID") as! String?
Bence Pattogato
fuente
2

Swift 3.0

if let path = Bundle.main.path(forResource: "config", ofType: "plist") {
    let dict = NSDictionary(contentsOfFile: path)

    // use dictionary
}

La forma más fácil de hacer esto en mi opinión.

malicioso
fuente
2

He creado un Dictionaryinicializador simple que reemplaza NSDictionary(contentsOfFile: path). Solo quite el NS.

extension Dictionary where Key == String, Value == Any {

    public init?(contentsOfFile path: String) {
        let url = URL(fileURLWithPath: path)

        self.init(contentsOfURL: url)
    }

    public init?(contentsOfURL url: URL) {
        guard let data = try? Data(contentsOf: url),
            let dictionary = (try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [String: Any]) ?? nil
            else { return nil }

        self = dictionary
    }

}

Puedes usarlo así:

let filePath = Bundle.main.path(forResource: "Preferences", ofType: "plist")!
let preferences = Dictionary(contentsOfFile: filePath)!
UserDefaults.standard.register(defaults: preferences)
Jordan H
fuente
2

Lista de Swift 4.0 iOS 11.2.6 analizada y código para analizarla, basada en https://stackoverflow.com/users/3647770/ashok-r respuesta anterior.

<?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">
<array>
  <dict>
    <key>identity</key>
    <string>blah-1</string>
    <key>major</key>
    <string>1</string>
    <key>minor</key>
    <string>1</string>
    <key>uuid</key>
    <string>f45321</string>
    <key>web</key>
    <string>http://web</string>
</dict>
<dict>
    <key>identity</key>
    <string></string>
    <key>major</key>
    <string></string>
    <key>minor</key>
    <string></string>
    <key>uuid</key>
    <string></string>
    <key>web</key>
    <string></string>
  </dict>
</array>
</plist>

do {
   let plistXML = try Data(contentsOf: url)
    var plistData: [[String: AnyObject]] = [[:]]
    var propertyListFormat =  PropertyListSerialization.PropertyListFormat.xml
        do {
            plistData = try PropertyListSerialization.propertyList(from: plistXML, options: .mutableContainersAndLeaves, format: &propertyListFormat) as! [[String:AnyObject]]

        } catch {
            print("Error reading plist: \(error), format: \(propertyListFormat)")
        }
    } catch {
        print("error no upload")
    }
usuario3069232
fuente
1

Paso 1 : forma simple y rápida de analizar plist en Swift 3+

extension Bundle {

    func parsePlist(ofName name: String) -> [String: AnyObject]? {

        // check if plist data available
        guard let plistURL = Bundle.main.url(forResource: name, withExtension: "plist"),
            let data = try? Data(contentsOf: plistURL)
            else {
                return nil
        }

        // parse plist into [String: Anyobject]
        guard let plistDictionary = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [String: AnyObject] else {
            return nil
        }

        return plistDictionary
    }
}

Paso 2: cómo usar:

Bundle().parsePlist(ofName: "Your-Plist-Name")
Bhuvan Bhatt
fuente
0

Aquí está la solución que encontré:

let levelBlocks = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("LevelBlocks", ofType: "plist"))
let test: AnyObject = levelBlocks.objectForKey("Level1")
println(test) // Prints the value of test

Configuré el tipo de testpara AnyObjectsilenciar una advertencia sobre una inferencia inesperada que podría ocurrir.

Además, debe hacerse en un método de clase.

Para acceder y guardar un valor específico de un tipo conocido:

let value = levelBlocks.objectForKey("Level1").objectForKey("amount") as Int
println(toString(value)) // Converts value to String and prints it
TheAppleMan
fuente
0

Uso diccionarios rápidos pero los convierto a NSDictionaries en mi clase de administrador de archivos de la siguiente manera:

    func writePlist(fileName:String, myDict:Dictionary<String, AnyObject>){
        let docsDir:String = dirPaths[0] as String
        let docPath = docsDir + "/" + fileName
        let thisDict = myDict as NSDictionary
        if(thisDict.writeToFile(docPath, atomically: true)){
            NSLog("success")
        } else {
            NSLog("failure")
        }

    }
    func getPlist(fileName:String)->Dictionary<String, AnyObject>{
        let docsDir:String = dirPaths[0] as String
        let docPath = docsDir + "/" + fileName
        let thisDict = NSDictionary(contentsOfFile: docPath)
        return thisDict! as! Dictionary<String, AnyObject>
    }

Esta parece la forma menos problemática de leer y escribir, pero dejemos que el resto de mi código se mantenga lo más rápido posible.

ew parris
fuente
0

Plist es una enumeración Swift simple que hice para trabajar con listas de propiedades.

// load an applications info.plist data

let info = Plist(NSBundle.mainBundle().infoDictionary)
let identifier = info["CFBundleIndentifier"].string!

Más ejemplos:

import Plist

// initialize using an NSDictionary
// and retrieve keyed values

let info = Plist(dict)
let name = info["name"].string ?? ""
let age = info["age"].int ?? 0


// initialize using an NSArray
// and retrieve indexed values

let info = Plist(array)
let itemAtIndex0 = info[0].value


// utility initiaizer to load a plist file at specified path
let info = Plist(path: "path_to_plist_file")

// we support index chaining - you can get to a dictionary from an array via
// a dictionary and so on
// don't worry, the following will not fail with errors in case
// the index path is invalid
if let complicatedAccessOfSomeStringValueOfInterest = info["dictKey"][10]["anotherKey"].string {
  // do something
}
else {
  // data cannot be indexed
}

// you can also re-use parts of a plist data structure

let info = Plist(...)
let firstSection = info["Sections"][0]["SectionData"]
let sectionKey = firstSection["key"].string!
let sectionSecret = firstSection["secret"].int!

Plist.swift

Plist en sí es bastante simple, aquí está su listado en caso de que lo refiera directamente.

//
//  Plist.swift
//


import Foundation


public enum Plist {

    case dictionary(NSDictionary)
    case Array(NSArray)
    case Value(Any)
    case none

    public init(_ dict: NSDictionary) {
        self = .dictionary(dict)
    }

    public init(_ array: NSArray) {
        self = .Array(array)
    }

    public init(_ value: Any?) {
        self = Plist.wrap(value)
    }

}


// MARK:- initialize from a path

extension Plist {

    public init(path: String) {
        if let dict = NSDictionary(contentsOfFile: path) {
            self = .dictionary(dict)
        }
        else if let array = NSArray(contentsOfFile: path) {
            self = .Array(array)
        }
        else {
            self = .none
        }
    }

}


// MARK:- private helpers

extension Plist {

    /// wraps a given object to a Plist
    fileprivate static func wrap(_ object: Any?) -> Plist {

        if let dict = object as? NSDictionary {
            return .dictionary(dict)
        }
        if let array = object as? NSArray {
            return .Array(array)
        }
        if let value = object {
            return .Value(value)
        }
        return .none
    }

    /// tries to cast to an optional T
    fileprivate func cast<T>() -> T? {
        switch self {
        case let .Value(value):
            return value as? T
        default:
            return nil
        }
    }
}

// MARK:- subscripting

extension Plist {

    /// index a dictionary
    public subscript(key: String) -> Plist {
        switch self {

        case let .dictionary(dict):
            let v = dict.object(forKey: key)
            return Plist.wrap(v)

        default:
            return .none
        }
    }

    /// index an array
    public subscript(index: Int) -> Plist {
        switch self {
        case let .Array(array):
            if index >= 0 && index < array.count {
                return Plist.wrap(array[index])
            }
            return .none

        default:
            return .none
        }
    }

}


// MARK:- Value extraction

extension Plist {

    public var string: String?       { return cast() }
    public var int: Int?             { return cast() }
    public var double: Double?       { return cast() }
    public var float: Float?         { return cast() }
    public var date: Date?         { return cast() }
    public var data: Data?         { return cast() }
    public var number: NSNumber?     { return cast() }
    public var bool: Bool?           { return cast() }


    // unwraps and returns the underlying value
    public var value: Any? {
        switch self {
        case let .Value(value):
            return value
        case let .dictionary(dict):
            return dict
        case let .Array(array):
            return array
        case .none:
            return nil
        }
    }

    // returns the underlying array
    public var array: NSArray? {
        switch self {
        case let .Array(array):
            return array
        default:
            return nil
        }
    }

    // returns the underlying dictionary
    public var dict: NSDictionary? {
        switch self {
        case let .dictionary(dict):
            return dict
        default:
            return nil
        }
    }

}


// MARK:- CustomStringConvertible

extension Plist : CustomStringConvertible {
    public var description:String {
        switch self {
        case let .Array(array): return "(array \(array))"
        case let .dictionary(dict): return "(dict \(dict))"
        case let .Value(value): return "(value \(value))"
        case .none: return "(none)"
        }
    }
}
Benzi
fuente
0

Swift 3.0

si desea leer una "matriz bidimensional" de .plist, puede intentarlo así:

if let path = Bundle.main.path(forResource: "Info", ofType: "plist") {
    if let dimension1 = NSDictionary(contentsOfFile: path) {
        if let dimension2 = dimension1["key"] as? [String] {
            destination_array = dimension2
        }
    }
}
Sandu
fuente
-2

Sencilla estructura de archivo de acceso plist (Swift 2.0)

struct Configuration {      
  static let path = NSBundle.mainBundle().pathForResource("Info", ofType: "plist")!
  static let dict = NSDictionary(contentsOfFile: path) as! [String: AnyObject]

  static let someValue = dict["someKey"] as! String
}

Uso:

print("someValue = \(Configuration.someValue)")
n0_quarter
fuente