ฉันจะรับ plist เป็น Dictionary ใน Swift ได้อย่างไร


198

ฉันกำลังเล่นกับภาษาการเขียนโปรแกรมSwiftใหม่ของ Apple และมีปัญหา ...

ขณะนี้ฉันกำลังพยายามอ่านไฟล์ plist ใน Objective-C ฉันจะทำสิ่งต่อไปนี้เพื่อรับเนื้อหาเป็น NSDictionary:

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

ฉันจะรับ plist เป็น Dictionary ใน Swift ได้อย่างไร

ฉันคิดว่าฉันสามารถหาเส้นทางไปยังผู้เล่นด้วย:

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

เมื่อใช้งานได้ (ถ้าถูกต้อง): ฉันจะรับเนื้อหาเป็นพจนานุกรมได้อย่างไร

คำถามทั่วไปเพิ่มเติม:

ตกลงเพื่อใช้คลาสNS *ดีฟอลต์หรือไม่ ฉันคิดว่างั้น ... เท่าที่ฉันทราบคลาสเฟรมเวิร์กNS *ดีฟอลต์ยังคงใช้ได้และใช้ได้


คำตอบนั้นไม่ถูกต้องอีกต่อไปคุณช่วยเลือกคำตอบของ Ashok ได้ไหม?
RodolfoAntonici

คำตอบ:


52

ในการอ่าน3.0 อย่างรวดเร็วจาก 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)")
        }
    }

อ่านเพิ่มเติม HOW รายการเพื่อใช้คุณสมบัติ (.plist) ใน SWIFT


Askok ลืมไปหลายชั่วโมงเพื่อหาคำตอบสำหรับสิ่งนี้ในวันนี้! ขอบคุณ!! มันทำงานได้อย่างสมบูรณ์แบบ !!!
3069232

282

คุณยังสามารถใช้ 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
}

NSClasses ยังคงมีอยู่และสมบูรณ์แบบที่จะใช้ใน Swift ฉันคิดว่าพวกเขาอาจต้องการเปลี่ยนโฟกัสไปที่รวดเร็วในไม่ช้า แต่ปัจจุบัน swift APIs ไม่มีฟังก์ชันการทำงานทั้งหมดของ NSClasses หลัก


อืมเมื่อฉันพยายามใช้รหัสที่คุณให้ผมได้รับข้อผิดพลาด: xxx ไม่มีสมาชิกชื่อ Dict
KennyVB

มันใช้งานได้ดีในสนามเด็กเล่น ไม่ใช่แค่ในเอกสารที่รวดเร็วของฉัน
KennyVB

ดูเหมือนว่า Array อย่างไร
Arnlee Vizcayno

ดูเหมือนว่าmainBundle()จะเป็นเพียงแค่mainใน Swift 3
BallpointBen

9
คำตอบนี้ล้าสมัยแล้ว แม้แต่ใน Swift 3 คุณไม่ควรใช้NSArray/NSDictionaryเลยเพื่ออ่านข้อมูลรายการคุณสมบัติ PropertyListSerialization(และใน Swift 4 หรือCodableโปรโตคอล) เป็น API ที่เหมาะสม ให้การจัดการข้อผิดพลาดที่ทันสมัยและข้อมูลสามารถแปลงเป็นประเภทการรวบรวม Swift ดั้งเดิมได้โดยตรง
Vadian

141

นี่คือสิ่งที่ฉันทำถ้าฉันต้องการแปลง. plist เป็น Swift dictionary:

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
}

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 สตริงที่มีคีย์ "ชื่อ", 1 Int พร้อมคีย์ "อายุ" และ 1 บูลีนที่มีคีย์ "เดี่ยว" นี่คือโครงสร้าง:

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 ดีกว่าตอนนี้เรามีอินสแตนซ์ของโครงสร้างการกำหนดค่าที่เราสามารถใช้ได้อย่างง่ายดาย:

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

สิ่งนี้พิมพ์ค่าสำหรับคีย์ "name", "age" และ "single" ใน. plist


1
นั่นเป็นคำตอบที่ดีที่สุดสำหรับ Swift 4 แต่ทำไมไม่ลองBundle.main.url(forResource: "Config", withExtension: "plist")กำจัดURL(fileURLWithPathล่ะ และเป็นไฟล์ที่จำเป็นต้องมีอยู่ (ณ เวลาออกแบบ / รวบรวม) ค่าทั้งหมดสามารถบังคับเปิดห่อ รหัสจะต้องไม่ผิดพลาดหากทุกอย่างได้รับการออกแบบอย่างถูกต้อง
vadian

@vadian แน่ใจว่าคุณสามารถใช้url(forResource: "Config", withExtension: "plist")ฉันแค่จับคู่สิ่งที่ OP ทำในรหัสของพวกเขาเป็นจุดเปรียบเทียบ ตราบใดที่การบังคับเปิดออกทุกอย่างฉันพยายามทำผิดด้านของความระมัดระวัง ฉันคิดว่านั่นเป็นคำถามพื้นฐานสำหรับ Swift โดยทั่วไป ฉันอยากรู้ว่าโค้ดของฉันจะทำอะไรในสถานการณ์ใด ๆ
ekreloff

1) โปรดอย่านำนิสัยที่ไม่ดีมาใช้หากมี API ที่เหมาะสมกว่า 2) เป็นหนึ่งในไม่กี่กรณีที่เกิดข้อผิดพลาดในการบังคับพบข้อผิดพลาดในการออกแบบ ไฟล์ใด ๆ ในบันเดิลจำเป็นต้องมีอยู่ ณ เวลารวบรวมและไม่สามารถเปลี่ยนแปลงได้ในขณะรันไทม์เนื่องจากไฟล์ทั้งหมดมีการลงนามรหัส อีกครั้งหนึ่งที่: รหัสต้องไม่ผิดพลาดถ้าทุกอย่างถูกออกแบบมาอย่างถูกต้อง
vadian

ใช่คุณรู้ว่าถูกต้อง ไม่ทราบว่าเป็นกรณีของทรัพยากร Bundle
ekreloff

2
@NaveenGeorgeThoppan หากคุณใช้ตัวอย่างนี้เป็นพจนานุกรมของคุณก็จะเป็นdecoder.decode([Config].self, from: data)เช่นนั้น (สังเกตเครื่องหมายวงเล็บรอบ [กำหนดค่า])
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

19

ฉันทำงานกับ Swift 3.0 และต้องการมีส่วนร่วมตอบคำตอบสำหรับไวยากรณ์ที่อัปเดตแล้ว นอกจากนี้และที่สำคัญกว่านั้นคือฉันใช้PropertyListSerializationวัตถุเพื่อยกของหนักซึ่งมีความยืดหยุ่นมากกว่าการใช้ NSDictionary เนื่องจากมันช่วยให้ Array เป็นชนิดรากของ plist

ด้านล่างนี้เป็นภาพหน้าจอของแผนการที่ฉันใช้ มันมีความซับซ้อนเล็กน้อยเพื่อที่จะแสดงพลังที่มีอยู่ แต่มันจะใช้ได้กับการผสมประเภท plist ที่อนุญาต

ตัวอย่างไฟล์ 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> >

และตอนนี้เราสามารถเข้าถึงคุณสมบัติต่าง ๆ ของ Array of String: พจนานุกรมสตริงได้อย่างเป็นธรรมชาติ หวังว่าจะแปลงให้เป็น struct หรือคลาสที่พิมพ์จริงอย่างยิ่งจริง ๆ )

print(dictArray[0]["Name"])

8

เป็นการดีที่สุดที่จะใช้พจนานุกรมและอาร์เรย์ดั้งเดิมเพราะได้รับการปรับให้เหมาะกับการใช้งานอย่างรวดเร็ว ที่ถูกกล่าวว่าคุณสามารถใช้ NS ... เรียนอย่างรวดเร็วและฉันคิดว่าสถานการณ์นี้รับประกันว่า นี่คือวิธีที่คุณจะใช้มัน:

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

จนถึงตอนนี้ (ในความคิดของฉัน) นี่เป็นวิธีที่ง่ายที่สุดและมีประสิทธิภาพมากที่สุดในการเข้าถึง Plist แต่ในอนาคตฉันคาดว่าแอปเปิ้ลจะเพิ่มฟังก์ชันการทำงานมากขึ้น (เช่นการใช้ Plist) ลงในพจนานุกรมท้องถิ่น


เท่าที่คุณรู้มีการเพิ่มการอ่านแบบเต็มไปยังพจนานุกรมท้องถิ่นที่เกิดขึ้นแล้ว?
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 ฉันต้องการเข้าถึงค่าบูลและทำให้เป็นจริง

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:

จาก Custom 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").

นี่คือสิ่งที่ฉันกำลังมองหา! ขอบคุณเพื่อน!
Jayprakash Dubey

6

แปลงเป็นส่วนขยายความสะดวกสบายผ่านคำตอบของ 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]
    }
}

การใช้งาน:

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

ฉันยินดีที่จะเดิมพันว่ามันจะทำงานเพื่อสร้างส่วนขยายที่คล้ายกันสำหรับอาร์เรย์


5

สามารถทำได้จริงใน 1 บรรทัด

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

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>

5

ตั้งแต่คำตอบนี้จะไม่อยู่ที่นี่ยังแค่อยากจะชี้ให้เห็นคุณยังสามารถใช้คุณสมบัติ infoDictionary เพื่อรับข้อมูล plist Bundle.main.infoDictionaryเป็นพจนานุกรม

แม้ว่าสิ่งที่ชอบBundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) อาจจะเร็วขึ้นหากคุณสนใจเฉพาะรายการใน Plist ข้อมูล

// 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 {

  }
}

ขอบคุณ objectForInfoDictionaryKeyเป็นสิ่งที่ฉันกำลังมองหา
LunaCodeGirl

2

คุณสามารถใช้สิ่งนั้นได้ฉันสร้างส่วนขยายอย่างง่ายสำหรับ Dictionary ใน 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
}

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
}

วิธีที่ง่ายที่สุดในการทำเช่นนี้ในความคิดของฉัน


2

ฉันได้สร้างง่ายๆDictionaryinitializer 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")
    }

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

0

ฉันใช้พจนานุกรม swift แต่แปลงให้เป็นและจาก 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>
    }

นี่เป็นวิธีที่น้อยที่สุดในการอ่านและเขียน


0

Plistเป็น Swift enum ง่ายๆที่ฉันทำเพื่อทำงานกับรายการคุณสมบัติ

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

0

Swift 3.0

ถ้าคุณต้องการอ่าน "Array 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
        }
    }
}

0

สวิฟท์ 5

หากคุณต้องการดึงค่าเฉพาะสำหรับบางคีย์เราสามารถใช้ส่วนขยายด้านล่างซึ่งใช้คุณสมบัติinfoDictionaryใน Bundle

Bundle.main.infoDictionaryสามารถใช้เพื่อรับค่า info.plist ทั้งหมดในพจนานุกรมรูปแบบและเพื่อให้เราสามารถสอบถามโดยตรงโดยใช้object(forInfoDictionaryKey: key)วิธีการใน Bundle

extension Bundle {
    static func infoPlistValue(forKey key: String) -> Any? {
        guard let value = Bundle.main.object(forInfoDictionaryKey: key) else {
           return nil
        }
        return value
    }
}

**How to Use:**

guard let apiURL = Bundle.infoPlistValue(forKey: "API_URL_KEY") as? String else { return }

-2

structอย่างง่ายในการเข้าถึงไฟล์ 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)")
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.