Jak uzyskać listę w słowniku Swift?

197

Bawię się nowym językiem programowania Swift firmy Apple i mam pewne problemy ...

Obecnie próbuję odczytać plik plist, w Objective-C zrobiłbym następujące, aby uzyskać zawartość jako NSDictionary:

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

Jak uzyskać listę w słowniku Swift?

Zakładam, że mogę uzyskać ścieżkę do plist za pomocą:

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

Kiedy to działa (jeśli jest poprawne?): Jak uzyskać treść jako słownik?

Także bardziej ogólne pytanie:

Czy można używać domyślnych klas NS * ? Tak mi się wydaje ... czy coś mi brakuje? O ile wiem domyślne klasy NS * frameworka są nadal prawidłowe i czy można ich używać?

Sebastian
źródło
Odpowiedź nie jest już ważna, czy możesz wybrać odpowiedź Ashoka?
RodolfoAntonici

Odpowiedzi:

51

W szybkim 3.0 Czytanie z 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)")
        }
    }

Czytaj więcej JAK KORZYSTAĆ Z LISTY NIERUCHOMOŚCI (.PLIST) W SWIFT .

Ashok R.
źródło
Askok. Straciłem wiele godzin, próbując dziś znaleźć na to odpowiedź! DZIĘKUJĘ CI!! To działało idealnie !!!
user3069232
281

Nadal możesz używać NSDictionaries w Swift:

Dla Swift 4

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

Dla Swift 3+

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

I starsze wersje 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
}

Klasy NSClass są nadal dostępne i doskonale nadają się do użycia w Swift. Myślę, że prawdopodobnie będą chcieli wkrótce skupić się na szybkim, ale obecnie szybkie interfejsy API nie mają wszystkich funkcji podstawowych NSClasses.

Connor
źródło
hmm, kiedy próbuję użyć tego kodu, który podałeś, pojawia się błąd: xxx nie ma członka o nazwie dict
KennyVB
działa dobrze na placu zabaw. po prostu nie w moim szybkim dokumencie
KennyVB,
jak to wygląda, jeśli Array?
Arnlee Vizcayno
Wygląda na mainBundle()to, że jest właśnie mainw Swift 3
BallpointBen
8
Ta odpowiedź jest nieaktualna. Nawet w Swift 3 nie powinieneś w ogóle używać NSArray/NSDictionarydo odczytu danych listy nieruchomości. PropertyListSerialization(aw Swift 4 alternatywnie Codableprotokół) jest odpowiednim API. Zapewnia nowoczesną obsługę błędów, a dane można konwertować bezpośrednio na rodzime typy kolekcji Swift.
vadian
141

Oto, co robię, jeśli chcę przekonwertować plik .plist na słownik 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
  }
}

Edytowane dla Swift 2.0:

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

Edytowane dla 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
źródło
3
Myślę, że jest to „najbardziej poprawna” odpowiedź w grupie, dopóki nie będzie natywnego szybkiego sposobu na zrobienie tego.
DudeOnRock
1
Ta odpowiedź jest nieaktualna. W Swift 3 nie powinieneś w ogóle używać NSArray/NSDictionarydo odczytu danych listy nieruchomości. PropertyListSerialization(aw Swift 4 alternatywnie Codableprotokół) jest odpowiednim API. Zapewnia nowoczesną obsługę błędów, a dane można konwertować bezpośrednio na rodzime typy kolekcji Swift.
vadian
47

Swift 4.0

Możesz teraz użyć protokołu dekodowania, aby zdekodować plik .plist do niestandardowej struktury. Przejdę do podstawowego przykładu, dla bardziej skomplikowanych struktur .plist, które polecam przeczytać na Decodable / Encodable (dobry zasób jest tutaj: https://benscheirman.com/2017/06/swift-json/ ).

Najpierw skonfiguruj swoją strukturę do formatu pliku .plist. W tym przykładzie rozważę .plist ze słownikiem na poziomie katalogu głównego i 3 wpisy: 1 Ciąg z kluczem „nazwa”, 1 Int z kluczem „wiek” i 1 Boolean z kluczem „pojedynczy”. Oto struktura:

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

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

Wystarczająco proste. Teraz fajna część. Za pomocą klasy PropertyListDecoder możemy łatwo parsować plik .plist w instancji tej struktury:

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

Niewiele więcej kodu do zmartwienia, a wszystko to w Swift. Jeszcze lepiej, mamy teraz instancję struktury Config, z której możemy łatwo korzystać:

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

Wyświetla wartość „nazwa”, „wiek” i „pojedyncze” klucze w .plist.

ekreloff
źródło
1
To najlepsza odpowiedź dla Swift 4. Ale dlaczego się nie Bundle.main.url(forResource: "Config", withExtension: "plist")pozbyć URL(fileURLWithPath? A ponieważ plik musi istnieć (w czasie projektowania / kompilacji), wszystkie wartości można wymusić rozpakowaniu. Kod nie może ulec awarii, jeśli wszystko jest poprawnie zaprojektowane.
wady
@vadian Jasne, że możesz użyć. url(forResource: "Config", withExtension: "plist")Właśnie porównywałem to, co OP zrobił w swoim kodzie. Jeśli chodzi o wymuszanie rozpakowywania wszystkiego, staram się zachować ostrożność. Myślę, że to podstawowe pytanie dla Swift w ogóle. Wolę wiedzieć dokładnie, co zrobi mój kod w każdej sytuacji niż awaria.
ekreloff
1) Nie stosuj złych nawyków, jeśli istnieje bardziej odpowiedni interfejs API. 2) To jeden z niewielu przypadków, w których wymuszona awaria wykrywa błąd projektowy. Każdy plik w pakiecie musi być obecny w czasie kompilacji i nie można go zmienić w czasie wykonywania, ponieważ wszystkie pliki są podpisane kodem. Jeszcze raz: kod nie może ulec awarii, jeśli wszystko jest poprawnie zaprojektowane .
vadian
Tak, znasz swoje prawo. Nie zdawałem sobie sprawy, że tak jest w przypadku zasobów pakietu.
ekreloff
2
@NaveenGeorgeThoppan, jeśli użyjesz tego przykładu jako słownika, to po prostu będzie decoder.decode([Config].self, from: data). (Zwróć uwagę na nawiasy
kwadratowe
22

Ta odpowiedź używa obiektów rodzimych Swift zamiast 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.
źródło
Czy jest w tym zwięzła wersja?
harsh_v
18

Pracowałem z Swift 3.0 i chciałem udzielić odpowiedzi na temat zaktualizowanej składni. Dodatkowo, a może co ważniejsze, używam obiektu PropertyListSerialization do ciężkiego podnoszenia, który jest o wiele bardziej elastyczny niż tylko używanie NSDictionary, ponieważ pozwala on na macierz jako typ główny plist.

Poniżej znajduje się zrzut ekranu z używanej listy. Jest to trochę skomplikowane, aby pokazać dostępną moc, ale będzie to działać dla każdej dopuszczalnej kombinacji typów plist.

Przykładowy plik plist Jak widać, używam słowników Array of String: String do przechowywania listy nazw witryn i odpowiadających im adresów URL.

Korzystam z obiektu PropertyListSerialization , jak wspomniano powyżej, aby wykonać dla mnie ciężkie podnoszenie. Ponadto Swift 3.0 stał się bardziej „Swifty”, więc wszystkie nazwy obiektów straciły prefiks „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)

Po uruchomieniu powyższego kodu plistbędzie on typu Array<AnyObject>, ale wiemy, jaki to naprawdę jest typ, więc możemy rzutować go na poprawny typ:

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

A teraz możemy uzyskać dostęp do różnych właściwości naszego Array of String: String Dictionaries w naturalny sposób. Mam nadzieję, że przekonwertuję je na rzeczywiste struktury lub klasy o silnym typie;)

print(dictArray[0]["Name"])
Nacięcie
źródło
8

Najlepiej jest używać rodzimych słowników i tablic, ponieważ zostały one zoptymalizowane do szybkiego użycia. Biorąc to pod uwagę, możesz szybko używać klas NS ... i myślę, że taka sytuacja to uzasadnia. Oto jak to zaimplementujesz:

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

Jak dotąd (moim zdaniem) jest to najłatwiejszy i najskuteczniejszy sposób dostępu do listy odtwarzania, ale w przyszłości spodziewam się, że Apple doda więcej funkcji (takich jak użycie listy odtwarzania) do rodzimych słowników.

67cherries
źródło
O ile wiesz, czy dodawanie odczytu plist do rodzimych słowników już się stało?
SpacyRicochet
8

Swift - Odczytywanie / zapisywanie listy i pliku tekstowego ....

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
źródło
8

Swift 2.0: Dostęp do Info.Plist

Mam słownik o nazwie CoachMarksDictionary z wartością logiczną w Info.Plist. Chcę uzyskać dostęp do wartości bool i sprawić, by była prawdziwa.

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

Writing To Plist:

Z niestandardowego listy: - (Utwórz z pliku-nowy-plik-zasób-lista właściwości. Dodano trzy ciągi nazwane: 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)
 }

Metodę można nazwać jako

self.writeToCoachMarksPlist(" true - means user has checked the marks",keyName: "the key in the CoachMarks dictionary").
AG
źródło
Właśnie tego szukałem! Dzięki stary!
Jayprakash Dubey,
6

Przekształcony w rozszerzenie wygody dzięki odpowiedzi Nicka:

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

stosowanie:

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

Byłbym skłonny się założyć, że to również zadziała, aby stworzyć podobne rozszerzenie dla tablic

mredig
źródło
5

mogę to zrobić w 1 linii

    var dict = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("Config", ofType: "plist"))
KennyVB
źródło
5

Możesz przeczytać plist w języku SWIFT w następujący sposób:

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

Czytaj wartość pojedynczego słownika:

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

Jeśli chcesz uzyskać pełny słownik wielowymiarowy w Plist:

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

Oto lista:

<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
źródło
5

Ponieważ ta odpowiedź nie jest tu jeszcze, po prostu chciałem podkreślić, można również użyć właściwości infoDictionary aby uzyskać informacje plist jako słownika Bundle.main.infoDictionary.

Chociaż coś takiego Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) może być szybsze, jeśli interesuje Cię tylko konkretny element na liście informacji.

// 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
źródło
3

w moim przypadku tworzę NSDictionarywywołanie appSettingsi dodam wszystkie potrzebne klucze. W tym przypadku rozwiązaniem jest:

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

  }
}
jose920405
źródło
Dzięki. objectForInfoDictionaryKeybyło dokładnie tym, czego szukałem.
LunaCodeGirl
2

Możesz z tego skorzystać, tworzę proste rozszerzenie słownika w 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
    }
}

I możesz użyć tego do obciążenia

/**
  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
źródło
2

Oto nieco krótsza wersja, oparta na odpowiedzi @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
źródło
2

Swift 3.0

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

    // use dictionary
}

Moim zdaniem najłatwiej to zrobić.

cichy
źródło
2

Stworzyłem prosty Dictionaryinicjalizator, który zastępuje NSDictionary(contentsOfFile: path). Po prostu usuń 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
    }

}

Możesz go używać w następujący sposób:

let filePath = Bundle.main.path(forResource: "Preferences", ofType: "plist")!
let preferences = Dictionary(contentsOfFile: filePath)!
UserDefaults.standard.register(defaults: preferences)
Jordan H.
źródło
2

Parsowana lista Swift 4.0 iOS 11.2.6 i kod do parsowania, na podstawie https://stackoverflow.com/users/3647770/ashok-r odpowiedzi powyżej.

<?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")
    }
użytkownik3069232
źródło
1

Krok 1 : Prosty i najszybszy sposób na parsowanie plist w szybkim 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
    }
}

Krok 2: Jak używać:

Bundle().parsePlist(ofName: "Your-Plist-Name")
Bhuvan Bhatt
źródło
0

Oto rozwiązanie, które znalazłem:

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

Ustawiam typ testnaAnyObject uciszyć ostrzeżenie o nieoczekiwanym wnioskowania, które mogą wystąpić.

Ponadto należy to zrobić metodą klasową.

Aby uzyskać dostęp i zapisać określoną wartość znanego typu:

let value = levelBlocks.objectForKey("Level1").objectForKey("amount") as Int
println(toString(value)) // Converts value to String and prints it
TheAppleMan
źródło
0

Używam szybkich słowników, ale konwertuję je do iz NSDictionaries w mojej klasie menedżera plików w następujący sposób:

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

To wydaje się najmniej kłopotliwy sposób na czytanie i pisanie, ale resztę mojego kodu pozostań tak szybko, jak to możliwe.

ew parris
źródło
0

Plist to proste wyliczenie Swift, które stworzyłem do pracy z listami właściwości.

// load an applications info.plist data

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

Więcej przykładów:

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

Sam Plist jest dość prosty, oto jego lista na wypadek, gdybyś odniósł się bezpośrednio.

//
//  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
źródło
0

Swift 3.0

jeśli chcesz przeczytać „2-dimensional Array” z .plist, możesz spróbować w następujący sposób:

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
źródło
-2

Prosta struktura dostępu do pliku 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
}

Stosowanie:

print("someValue = \(Configuration.someValue)")
n0_quarter
źródło