Comment obtenir un plist en tant que dictionnaire dans Swift?

197

Je joue avec le nouveau langage de programmation Swift d' Apple et j'ai quelques problèmes ...

Actuellement, j'essaie de lire un fichier plist, dans Objective-C, je ferais ce qui suit pour obtenir le contenu en tant que NSDictionary:

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

Comment obtenir un plist en tant que dictionnaire dans Swift?

Je suppose que je peux obtenir le chemin vers le plist avec:

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

Quand cela fonctionne (si c'est correct?): Comment puis-je obtenir le contenu sous forme de dictionnaire?

Aussi une question plus générale:

Est-il correct d'utiliser les classes NS * par défaut ? Je pense que oui ... ou est-ce que je manque quelque chose? Autant que je sache, les classes NS * du framework par défaut sont toujours valides et correctes?

Sébastien
la source
La réponse n'est plus valide, pourriez-vous s'il vous plaît sélectionner la réponse de l'Ashok?
RodolfoAntonici

Réponses:

51

Dans swift 3.0 Reading from 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)")
        }
    }

En savoir plus COMMENT UTILISER LES LISTES DE PROPRIÉTÉ (.PLIST) DANS SWIFT .

Ashok R
la source
Askok. J'ai perdu de nombreuses heures à essayer de trouver une réponse à cela aujourd'hui! MERCI!! Cela a parfaitement fonctionné !!!
user3069232
281

Vous pouvez toujours utiliser NSDictionaries dans Swift:

Pour Swift 4

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

Pour Swift 3+

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

Et les anciennes versions 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
}

Les NSClasses sont toujours disponibles et parfaitement adaptés à Swift. Je pense qu'ils voudront probablement changer d'orientation rapidement, mais actuellement les API rapides n'ont pas toutes les fonctionnalités des NSClasses de base.

Connor
la source
hmm quand j'essaie d'utiliser le code que vous avez fourni, j'obtiens l'erreur: xxx n'a pas de membre nommé dict
KennyVB
cela fonctionne bien dans le terrain de jeu. tout simplement pas dans mon document rapide
KennyVB
à quoi ça ressemble si Array?
Arnlee Vizcayno
On dirait que mainBundle()c'est juste maindans Swift 3
BallpointBen
8
Cette réponse est dépassée. Même dans Swift 3, vous ne devez pas du tout utiliser NSArray/NSDictionarypour lire les données de la liste des propriétés. PropertyListSerialization(et dans Swift 4 alternativement le Codableprotocole) est l'API appropriée. Il offre une gestion moderne des erreurs et les données peuvent être converties directement en types de collection Swift natifs.
vadian
141

Voici ce que je fais si je veux convertir un .plist en un dictionnaire 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
  }
}

Modifié pour Swift 2.0:

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

Modifié pour 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
la source
3
Je pense que c'est la réponse "la plus correcte" du groupe jusqu'à ce qu'il y ait une façon rapide et native de le faire.
DudeOnRock
1
Cette réponse est dépassée. Dans Swift 3, vous ne devez pas du tout utiliser NSArray/NSDictionarypour lire les données de la liste des propriétés. PropertyListSerialization(et dans Swift 4 alternativement le Codableprotocole) est l'API appropriée. Il offre une gestion moderne des erreurs et les données peuvent être converties directement en types de collection Swift natifs.
vadian
47

Swift 4.0

Vous pouvez maintenant utiliser le protocole Decodable pour décoder un .plist dans une structure personnalisée. Je vais passer en revue un exemple de base, pour les structures .plist plus compliquées, je recommande de lire sur Decodable / Encodable (une bonne ressource est ici: https://benscheirman.com/2017/06/swift-json/ ).

Configurez d'abord votre structure au format de votre fichier .plist. Pour cet exemple, je considérerai un .plist avec un dictionnaire de niveau racine et 3 entrées: 1 chaîne avec la clé "nom", 1 int avec la clé "age" et 1 booléen avec la clé "single". Voici la structure:

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

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

Assez simple. Maintenant, la partie cool. En utilisant la classe PropertyListDecoder, nous pouvons facilement analyser le fichier .plist dans une instanciation de cette structure:

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)
}

Pas beaucoup plus de code à se soucier, et tout est dans Swift. Mieux encore, nous avons maintenant une instanciation de la structure Config que nous pouvons facilement utiliser:

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

Cela imprime la valeur des clés "nom", "âge" et "unique" dans le .plist.

ekreloff
la source
1
C'est la meilleure réponse pour Swift 4. Mais pourquoi pas Bundle.main.url(forResource: "Config", withExtension: "plist")et s'en débarrasser URL(fileURLWithPath? Et comme le fichier doit exister (au moment de la conception / compilation), toutes les valeurs peuvent être forcées à être dépliées. Le code ne doit pas planter si tout est correctement conçu.
2018
@vadian Bien sûr, vous pouvez utiliser url(forResource: "Config", withExtension: "plist")Je faisais juste correspondre ce que l'OP a fait dans leur code comme point de comparaison. Pour ce qui est de tout déballer de force, j'essaie de faire preuve de prudence. Je pense que c'est une question fondamentale pour Swift en général. Je préfère savoir exactement ce que mon code fera dans n'importe quelle situation plutôt que de planter.
ekreloff
1) Veuillez ne pas adopter de mauvaises habitudes s'il existe une API plus appropriée. 2) C'est l'un des rares cas où un crash forcé découvre une erreur de conception. Tout fichier du bundle doit être présent au moment de la compilation et ne peut pas être modifié au moment de l'exécution car tous les fichiers sont signés par code. Encore une fois: le code ne doit pas planter si tout est correctement conçu .
vadian
Oui, vous connaissez votre droit. Je ne savais pas que c'était le cas avec les ressources Bundle.
ekreloff
2
@NaveenGeorgeThoppan si vous utilisez cet exemple comme dictionnaire, ce serait tout simplement decoder.decode([Config].self, from: data). (Notez les crochets autour de [Config])
ekreloff
22

Cette réponse utilise des objets natifs Swift plutôt que 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.
la source
Existe-t-il une version concise de cela?
harsh_v
18

J'ai travaillé avec Swift 3.0 et je voulais apporter une réponse à la syntaxe mise à jour. De plus, et peut-être plus important encore, j'utilise l' objet PropertyListSerialization pour faire le gros du travail, ce qui est beaucoup plus flexible que de simplement utiliser NSDictionary car il permet un tableau comme type racine du plist.

Voici une capture d'écran de la liste que j'utilise. C'est un peu compliqué, afin de montrer la puissance disponible, mais cela fonctionnera pour n'importe quelle combinaison autorisée de types de plist.

Exemple de fichier plist Comme vous pouvez le voir, j'utilise un ensemble de dictionnaires String: String pour stocker une liste de noms de sites Web et leur URL correspondante.

J'utilise l' objet PropertyListSerialization , comme mentionné ci-dessus, pour faire le gros du travail pour moi. De plus, Swift 3.0 est devenu plus "Swifty", donc tous les noms d'objets ont perdu le préfixe "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)

Une fois le code ci-dessus exécuté, plistil sera de type Array<AnyObject>, mais nous savons de quel type il s'agit vraiment afin que nous puissions le convertir au type correct:

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

Et maintenant, nous pouvons accéder aux différentes propriétés de notre Array of String: String Dictionaries de manière naturelle. Espérons les convertir en structures ou classes réelles fortement typées;)

print(dictArray[0]["Name"])
pseudo
la source
8

Il est préférable d'utiliser des dictionnaires et des tableaux natifs car ils ont été optimisés pour une utilisation avec swift. Cela étant dit, vous pouvez utiliser les classes NS ... rapidement et je pense que cette situation le justifie. Voici comment vous le mettriez en œuvre:

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

Jusqu'à présent (à mon avis), c'est le moyen le plus simple et le plus efficace d'accéder à un plist, mais à l'avenir, je m'attends à ce qu'Apple ajoute plus de fonctionnalités (comme l'utilisation de plist) dans les dictionnaires natifs.

67cherries
la source
À votre connaissance, l'ajout de la lecture de plist aux dictionnaires natifs s'est-il déjà produit?
SpacyRicochet
8

Swift - Lecture / écriture plist et fichier texte ....

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
la source
8

Swift 2.0: Accès à Info.Plist

J'ai un dictionnaire nommé CoachMarksDictionary avec une valeur booléenne dans Info.Plist. Je veux accéder à la valeur booléenne et la rendre vraie.

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) ")
  }

Ecrire à Plist:

À partir d'une liste personnalisée: - (Créer à partir de File-New-File-Resource-PropertyList. Ajout de trois chaînes nommées: 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)
 }

La méthode peut être appelée comme

self.writeToCoachMarksPlist(" true - means user has checked the marks",keyName: "the key in the CoachMarks dictionary").
AG
la source
C'est ce que je cherchais! Merci mon pote!
Jayprakash Dubey
6

Converti en une extension de commodité via la réponse 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]
    }
}

usage:

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

Je serais prêt à parier que cela fonctionnerait également pour créer une extension similaire pour les tableaux

mredig
la source
5

peut réellement le faire en 1 ligne

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

Vous pouvez lire plist dans SWIFT Language de cette manière:

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

Lire la valeur du dictionnaire unique:

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

Si vous souhaitez obtenir un dictionnaire multidimensionnel complet dans plist:

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

Voici le 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
la source
5

Étant donné que cette réponse est pas encore là, je voulais juste faire remarquer , vous pouvez également utiliser la propriété infoDictionary pour obtenir le plist info comme un dictionnaire, Bundle.main.infoDictionary.

Bien que quelque chose comme cela Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) puisse être plus rapide si vous n'êtes intéressé que par un élément spécifique dans la liste d'informations.

// 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
la source
3

dans mon cas, je crée un NSDictionaryappelé appSettingset ajoute toutes les clés nécessaires. Dans ce cas, la solution est:

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

  }
}
jose920405
la source
Merci. objectForInfoDictionaryKeyétait exactement ce que je cherchais.
LunaCodeGirl
2

Vous pouvez l'utiliser, je crée une extension simple pour Dictionary dans 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
    }
}

Et vous pouvez l'utiliser pour charger

/**
  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
la source
2

Voici une version un peu plus courte, basée sur la réponse 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
la source
2

Swift 3.0

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

    // use dictionary
}

La façon la plus simple de le faire à mon avis.

quemeful
la source
2

J'ai créé un simple Dictionaryinitialiseur qui remplace NSDictionary(contentsOfFile: path). Retirez simplement le 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
    }

}

Vous pouvez l'utiliser comme ceci:

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

Swift 4.0 iOS 11.2.6 liste analysée et code pour l'analyser, basé sur la réponse https://stackoverflow.com/users/3647770/ashok-r ci-dessus.

<?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")
    }
user3069232
la source
1

Étape 1 : moyen simple et rapide d'analyser le plist dans 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
    }
}

Étape 2: Comment utiliser:

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

Voici la solution que j'ai trouvée:

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

J'ai défini le type de testpour AnyObjectfaire taire un avertissement concernant une inférence inattendue qui pourrait se produire.

De plus, cela doit être fait dans une méthode de classe.

Pour accéder et enregistrer une valeur spécifique d'un type connu:

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

J'utilise des dictionnaires rapides mais les convertis vers et depuis NSDictionaries dans ma classe de gestionnaire de fichiers comme ceci:

    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>
    }

Cela semble la façon la moins troublante de lire et d'écrire, mais laissons le reste de mon code aussi rapide que possible.

ew parris
la source
0

Plist est une énumération Swift simple que j'ai faite pour travailler avec des listes de propriétés.

// load an applications info.plist data

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

Plus d'exemples:

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 lui-même est assez simple, voici sa liste au cas où vous vous référeriez directement.

//
//  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
la source
0

Swift 3.0

si vous voulez lire un "tableau bidimensionnel" de .plist, vous pouvez l'essayer comme ceci:

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
la source
-2

Structure simple pour accéder au fichier 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
}

Usage:

print("someValue = \(Configuration.someValue)")
n0_quarter
la source