Как мне получить список в качестве словаря в Swift?

197

Я играю с новым Swift от Apple языком программирования и у меня есть некоторые проблемы ...

В настоящее время я пытаюсь прочитать файл plist, в Objective-C я бы сделал следующее, чтобы получить содержимое в виде NSDictionary:

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

Как мне получить список в качестве словаря в Swift?

Я предполагаю, что могу получить путь к списку с помощью:

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

Когда это работает (если это правильно?): Как получить контент в качестве словаря?

Также более общий вопрос:

Можно ли использовать классы NS * по умолчанию ? Я так думаю ... или я что-то упустил? Насколько я знаю, стандартные рамки NS * классы все еще действительны и в порядке?

Себастьян
источник
Ответ больше не действителен, не могли бы вы выбрать ответ Ашока?
RodolfoAntonici

Ответы:

51

В Свифт 3.0 Чтение из Плиста.

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

Прочитайте больше КАК ИСПОЛЬЗОВАТЬ СПИСКИ НЕДВИЖИМОСТИ (.PLIST) В SWIFT .

Ашок Р
источник
Askok. Потерял много часов, пытаясь найти ответ на этот вопрос сегодня! СПАСИБО!! Это сработало отлично !!!
user3069232
281

Вы все еще можете использовать NSDictionaries в Swift:

Для Swift 4

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

Для Swift 3+

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

И старые версии 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
}

Классы NSC по-прежнему доступны и отлично подходят для использования в Swift. Я думаю, что они, вероятно, скоро захотят сместить фокус на swift, но в настоящее время быстрые API не обладают всей функциональностью базовых NSClasses.

Коннор
источник
хм, когда я пытаюсь использовать тот код, который вы предоставили, я получаю сообщение об ошибке: xxx не имеет члена с именем dict
KennyVB
Он прекрасно работает на детской площадке. только не в моем быстром документе
KennyVB
Как это выглядит, если Array?
Арнли Бискайно,
Похоже , mainBundle()это как раз mainв Swift 3
BallpointBen
8
Этот ответ устарел. Даже в Swift 3 вы вообще не должны использовать NSArray/NSDictionaryданные списка свойств. PropertyListSerialization(и в Swift 4 альтернативно Codableпротокол) является соответствующим API. Он обеспечивает современную обработку ошибок, и данные могут быть преобразованы непосредственно в собственные типы коллекций Swift.
vadian
141

Вот что я делаю, если хочу преобразовать .plist в словарь 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
  }
}

Отредактировано для Swift 2.0:

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

Отредактировано для 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
источник
3
Я думаю, что это «самый правильный» ответ из всех, до тех пор, пока не найдется быстрый и быстрый способ сделать это.
DudeOnRock
1
Этот ответ устарел. В Swift 3 вы вообще не должны использовать NSArray/NSDictionaryдля чтения данных списка свойств. PropertyListSerialization(и в Swift 4 альтернативно Codableпротокол) является соответствующим API. Он обеспечивает современную обработку ошибок, и данные могут быть преобразованы непосредственно в собственные типы коллекций Swift.
vadian
47

Swift 4.0

Теперь вы можете использовать Decodable протокол для декодирования .plist в пользовательскую структуру. Я рассмотрю базовый пример, для более сложных структур .plist, которые я рекомендую прочитать в Decodable / Encodable (хороший ресурс здесь: https://benscheirman.com/2017/06/swift-json/ ).

Сначала настройте вашу структуру в формате вашего файла .plist. Для этого примера я рассмотрю .plist с словарём корневого уровня и 3 записями: 1 строка с ключом «name», 1 Int с ключом «age» и 1 Boolean с ключом «single». Вот структура:

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

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

Достаточно просто. Теперь классная часть. Используя класс PropertyListDecoder, мы можем легко проанализировать файл .plist для создания этой структуры:

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

Не намного больше кода для беспокойства, и все это в Swift. Более того, теперь у нас есть экземпляр структуры Config, которую мы можем легко использовать:

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

Это печатает значение для ключей «name», «age» и «single» в .plist.

ekreloff
источник
1
Это лучший ответ для Swift 4. Но почему бы Bundle.main.url(forResource: "Config", withExtension: "plist")и не избавиться URL(fileURLWithPath? И поскольку файл должен существовать (во время разработки / компиляции), все значения можно принудительно развернуть. Код не должен падать, если все спроектировано правильно.
Vadian
@vadian Конечно, вы можете использовать, url(forResource: "Config", withExtension: "plist")я просто сопоставлял то, что ОП сделал в своем коде, для сравнения. Что касается силы, разворачивающей все, я стараюсь ошибиться в сторону осторожности. Я думаю, что это основной вопрос для Swift в целом. Я предпочел бы точно знать, что мой код будет делать в любой ситуации, чем сбой.
ekreloff
1) Пожалуйста, не принимайте вредных привычек, если есть более подходящий API. 2) Это один из немногих случаев, когда принудительный сбой обнаруживает ошибку проектирования. Любой файл в пакете должен присутствовать во время компиляции и не может быть изменен во время выполнения, поскольку все файлы имеют кодовую подпись. Еще раз: код не должен падать, если все спроектировано правильно .
vadian
Да, вы знаете свое право. Не понимал, что это было с ресурсами Bundle.
ekreloff
2
@NaveenGeorgeThoppan, если вы используете этот пример в качестве словаря, то он просто будет decoder.decode([Config].self, from: data). (Обратите внимание на квадратные скобки вокруг [Config])
ekreloff
22

Этот ответ использует нативные объекты Swift, а не 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"] ?? ""
Томми С.
источник
Есть ли краткая версия к этому?
harsh_v
18

Я работал с Swift 3.0 и хотел предоставить ответ на обновленный синтаксис. Кроме того, и, возможно, что еще более важно, я использую PropertyListSerialization объект для выполнения тяжелой работы, которая намного более гибкая, чем просто использование NSDictionary, поскольку она позволяет использовать массив как корневой тип plist.

Ниже приведен скриншот используемого мной списка. Это немного сложно, чтобы показать доступную мощность, но это будет работать для любой допустимой комбинации типов списков.

Образец списка файлов Как вы можете видеть, я использую словари Array of String: String для хранения списка названий веб-сайтов и соответствующих им URL.

Я использую объект PropertyListSerialization , как упоминалось выше, чтобы сделать тяжелую работу для меня. Кроме того, Swift 3.0 стал более «Swifty», поэтому все имена объектов потеряли префикс «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)

После того как приведенный выше код plistбудет иметь тип Array<AnyObject>, но мы знаем, какой это действительно тип, поэтому мы можем привести его к правильному типу:

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

И теперь мы можем получить доступ к различным свойствам нашего массива строк: строковых словарей естественным образом. Надеюсь превратить их в настоящие строго типизированные структуры или классы;)

print(dictArray[0]["Name"])
Ник
источник
8

Лучше всего использовать собственные словари и массивы, потому что они были оптимизированы для использования с swift. Тем не менее, вы можете использовать NS ... классы быстро, и я думаю, что эта ситуация оправдывает это. Вот как вы бы это реализовали:

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

До сих пор (на мой взгляд) это самый простой и эффективный способ доступа к списку рассылки, но в будущем я ожидаю, что Apple добавит больше функциональности (например, использование plist) в родные словари.

67cherries
источник
Насколько вы знаете, добавление чтения списков в родные словари уже произошло?
SpacyRicochet
8

Swift - чтение / запись списков и текстовых файлов ....

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")
    }
}
Нитин Сатьян
источник
8

Swift 2.0: доступ к Info.Plist

У меня есть словарь с именем CoachMarksDictionary с логическим значением в Info.Plist. Я хочу получить доступ к значению bool и сделать это правдой.

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

Запись в Plist:

Из пользовательского Plist: - (Сделать из File-New-File-Resource-PropertyList. Добавлены три строки с именами: 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)
 }

Метод можно назвать как

self.writeToCoachMarksPlist(" true - means user has checked the marks",keyName: "the key in the CoachMarks dictionary").
AG
источник
Это то, что я искал! Спасибо дружище!
Джайпракаш Дубей
6

Преобразован в удобное расширение через ответ Ника:

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

использование:

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

Я был бы готов поспорить, что это также будет работать для создания аналогичного расширения для массивов

mredig
источник
5

на самом деле может сделать это в 1 строку

    var dict = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("Config", ofType: "plist"))
KennyVB
источник
5

Вы можете прочитать plist на языке SWIFT следующим образом:

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

Считать значение из одного словаря

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

Если вы хотите получить полный многомерный словарь в plist:

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

Вот этот лист

<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
источник
5

Так как этого ответа еще нет, просто хочу отметить, что вы также можете использовать свойство infoDictionary для получения информационного списка в качестве словаря Bundle.main.infoDictionary.

Хотя что-то подобное Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) может быть быстрее, если вас интересует только конкретный элемент в информационном листе.

// 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)
Скотт Марчант
источник
3

в моем случае я создаю NSDictionaryвызываемый appSettingsи добавляю все необходимые ключи. Для этого случая решение:

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

  }
}
jose920405
источник
Спасибо. objectForInfoDictionaryKeyбыло именно то, что я искал.
LunaCodeGirl
2

Вы можете использовать это, я создаю простое расширение для словаря в 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
    }
}

И вы можете использовать это для загрузки

/**
  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
источник
2

Вот немного более короткая версия, основанная на ответе @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?
Бенс Паттогато
источник
2

Swift 3.0

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

    // use dictionary
}

Самый простой способ сделать это, на мой взгляд.

quemeful
источник
2

Я создал простой Dictionaryинициализатор, который заменяет NSDictionary(contentsOfFile: path). Просто удалите 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
    }

}

Вы можете использовать это так:

let filePath = Bundle.main.path(forResource: "Preferences", ofType: "plist")!
let preferences = Dictionary(contentsOfFile: filePath)!
UserDefaults.standard.register(defaults: preferences)
Джордан Х
источник
2

Проанализированный список Swift 4.0 для iOS 11.2.6 и код для его анализа основаны на ответе https://stackoverflow.com/users/3647770/ashok-r выше.

<?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
источник
1

Шаг 1 : Простой и быстрый способ разбора plist в 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
    }
}

Шаг 2: Как использовать:

Bundle().parsePlist(ofName: "Your-Plist-Name")
Бхуван Бхатт
источник
0

Вот решение, которое я нашел:

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

Я установил тип testна, AnyObjectчтобы заставить замолчать предупреждение о неожиданном выводе, который может произойти.

Кроме того, это должно быть сделано в методе класса.

Чтобы получить доступ и сохранить определенное значение известного типа:

let value = levelBlocks.objectForKey("Level1").objectForKey("amount") as Int
println(toString(value)) // Converts value to String and prints it
TheAppleMan
источник
0

Я использую быстрые словари, но конвертирую их в и из NSDictionaries в моем классе файлового менеджера следующим образом:

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

Это кажется наименее тревожным способом чтения и записи, но остальная часть моего кода останется настолько быстрой, насколько это возможно.

EW Parris
источник
0

Plist - это простое перечисление Swift, которое я сделал для работы со списками свойств.

// load an applications info.plist data

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

Больше примеров:

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 довольно прост, вот его список на тот случай, если вы будете ссылаться напрямую.

//
//  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
источник
0

Swift 3.0

Если вы хотите прочитать «2-мерный массив» из .plist, вы можете попробовать это так:

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
        }
    }
}
Санду
источник
-2

Простая структура для доступа к файлу 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
}

Использование:

print("someValue = \(Configuration.someValue)")
n0_quarter
источник