【问题标题】:How to read from a plist with Swift 3 iOS app如何使用 Swift 3 iOS 应用程序从 plist 中读取
【发布时间】:2017-02-16 01:15:59
【问题描述】:

-免责声明-
我对 iOS 和 Swift 开发非常陌生,但我对编程并不是特别陌生。

我有一个基本的iOS 应用程序,其中包含Swift3 元素。
我创建了一个plist 文件,其中包含一些我想在我的应用程序中读取和显示的条目。 (无需写入权限)

如何在 Swift3 中为捆绑的 plist 文件读取给定键的值?

这对我来说似乎是一个非常简单的问题,但一堆搜索让我质疑我的整个概念方法。

我们将不胜感激。

【问题讨论】:

  • 上面提到的反叛者网站是一个链接到一个图书馆来处理这些事情。这可能很棒,我不知道,但它肯定是一篇很长的文章,描述了一个比这个过程应该需要的复杂得多的过程。在这一天,第二个网站对我来说是一个死链接。

标签: ios swift xcode plist swift3


【解决方案1】:

与您在 Swift 2.3 或更低版本中所做的相同,只是语法发生了变化。

if let path = Bundle.main.path(forResource: "fileName", ofType: "plist") {

    //If your plist contain root as Array
    if let array = NSArray(contentsOfFile: path) as? [[String: Any]] {

    }

    ////If your plist contain root as Dictionary
    if let dic = NSDictionary(contentsOfFile: path) as? [String: Any] {

    }
}

注意:在 Swift 中,最好使用 Swift 的泛型类型 Array 和 Dictionary 而不是 NSArrayNSDictionary

编辑: 除了NSArray(contentsOfFile: path)NSDictionary(contentsOfFile:),我们还可以使用PropertyListSerialization.propertyList(from:)plist 文件中读取数据。

if let fileUrl = Bundle.main.url(forResource: "fileName", withExtension: "plist"),
   let data = try? Data(contentsOf: fileUrl) {
       if let result = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [[String: Any]] { // [String: Any] which ever it is 
            print(result)
       }
}

【讨论】:

  • 非常感谢。我找到了很多关于 Swift != 3 的示例。我很担心采用 Swift,因为我还听说它在其短暂的生命中进行了两次相当大的重新装修。
  • @Doc 值得注意的是,一些 plist 是预定义的。最值得注意的是 info.plist :static let BASE_URL = Bundle.main.infoDictionary!["MY_BASE_URL"] as! String
  • 为了强调@Dilapidus 的非常好的观点,这个问题的正确/接受的答案应该基于Bundle.main.infoDictionary ...它就在那里等着你。无需更多代码。
【解决方案2】:

随着 Swift 4 引入 可编码

第 1 步:从包中加载 Plist 文件。

第 2 步:使用 PropertyListDecoder 将属性列表值解码为语义 Decodable 类型。

第 3 步:创建可编码结构

完整代码-

 func setData() {
        // location of plist file
        if let settingsURL = Bundle.main.path(forResource: "JsonPlist", ofType: "plist") {

            do {
                var settings: MySettings?
                let data = try Data(contentsOf: URL(fileURLWithPath: settingsURL))
                    let decoder = PropertyListDecoder()
                settings = try decoder.decode(MySettings.self, from: data)
                    print("toolString is \(settings?.toolString ?? "")")
                print("DeviceDictionary is \(settings?.deviceDictionary?.phone ?? "")")
                print("RootPartArray is \(settings?.RootPartArray ?? [""])")

            } catch {
                print(error)
            }
        }
    }
}
struct MySettings: Codable {
    var toolString: String?
    var deviceDictionary: DeviceDictionary?
    var RootPartArray: [String]?

    private enum CodingKeys: String, CodingKey {
        case toolString = "ToolString"
        case deviceDictionary = "DeviceDictionary"
        case RootPartArray
    }

    struct DeviceDictionary: Codable {
        var phone: String?
        init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            phone = try values.decodeIfPresent(String.self, forKey: .phone)
        }
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        toolString = try values.decodeIfPresent(String.self, forKey: .toolString)
        deviceDictionary = try values.decodeIfPresent(DeviceDictionary.self, forKey: .deviceDictionary)
        RootPartArray = try values.decodeIfPresent([String].self, forKey: .RootPartArray)

    }
}

示例 Plist 文件 -> https://gist.github.com/janeshsutharios/4b0fb0e3edeff961d3e1f2829eb518db

【讨论】:

  • 我认为将其保存到 NSDictionary 或 Dictionary 时性能更好?
  • Codable 是 Apple 的最佳选择
【解决方案3】:

这是一个基于Nirav D's answerSwift 3实现:

    /// Read Plist File.
    ///
    /// - Parameter fileURL: file URL.
    /// - Returns: return plist content.
    func ReadPlist(_ fileURL: URL) -> [String: Any]? {
        guard fileURL.pathExtension == FileExtension.plist, let data = try? Data(contentsOf: fileURL) else {
            return nil
        }
        guard let result = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [String: Any] else {
            return nil
        }
        print(result)
        return result
    }

【讨论】:

  • 感谢您的新建议。请您告诉我这与 Nirav D 的答案有何不同?我喜欢你涉及异常处理。基本上是这样吗?
  • @JamesTSnell 谢谢你的提问。两个答案基本一致。我只是将他的答案抽象为一个方便调用的函数。 Nirav D 的回答没有处理异常或错误。所以在我的函数中,如果发生了一些不好的事情将返回 nil。希望得到帮助。
【解决方案4】:

这里是如何从 Info plist 中获取 BundleID 的示例:

var appBundleID = "Unknown Bundle ID"    
if let bundleDict = Bundle.main.infoDictionary, 
   let bundleID = bundleDict[kCFBundleIdentifierKey as String] as? String {
       appBundleID = bundleID
   }

您可以通过同样的方式轻松访问任何密钥。这种方法适用于多目标项目。

【讨论】:

    【解决方案5】:

    对于 Swift 3.0,以下代码直接定位到键。 dict 对象将提供 plist 文件中的所有内容。

    if let path = Bundle.main.path(forResource: "YourPlistFile", ofType: "plist"), let dict = NSDictionary(contentsOfFile: path) as? [String: AnyObject] {
                let value = dict["KeyInYourPlistFile"] as! String
        }
    

    【讨论】:

      【解决方案6】:

      在 AppDelegate 文件中

      var bundlePath:String!
          var documentPath:String!
          var plistDocumentPath:URL!
          let fileManager = FileManager()
      
      
          func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
          {
              bundlePath = Bundle.main.path(forResource: "Team", ofType: "plist")
      
              documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
      
              plistDocumentPath = URL.init(string: documentPath)?.appendingPathComponent("Team.plist")
              print(plistDocumentPath.path)
      
              if !fileManager.fileExists(atPath: plistDocumentPath.path){
      
                  do {
                      try fileManager.copyItem(atPath: bundlePath, toPath: plistDocumentPath.path)
                  } catch  {
                      print("error Occured \(error.localizedDescription)")
                  }
      
              }
      
      
              return true
          }
      

      在 ViewController 中

       @IBOutlet weak var TeamTable: UITableView!
          var appDelegate:AppDelegate!
          var arrayForContacts:[[String:Any]]! // array object
      
      
          override func viewDidLoad() {
              super.viewDidLoad()
      
      
      
      
              appDelegate = UIApplication.shared.delegate as! AppDelegate
      
      
          }
          override func viewWillAppear(_ animated: Bool) {
      
              super.viewWillAppear(animated)
      
              if appDelegate.fileManager.fileExists(atPath: appDelegate.plistDocumentPath.path){
                  arrayForContacts = []
                  if let contentOfPlist = NSArray.init(contentsOfFile: appDelegate.plistDocumentPath.path ){
                      arrayForContacts = contentOfPlist as! [[String:Any]]
                      TeamTable.reloadData()
                  }
      
              }
          }
      

      【讨论】:

        【解决方案7】:

        您也可以直接从您的 plist 文件中读取值,只需

        let value = Bundle.init(for: AppDelegate.self).infoDictionary?["your plist key name"] as? Any
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-09-25
          • 2017-03-19
          • 1970-01-01
          • 2015-10-22
          • 1970-01-01
          • 2017-09-26
          相关资源
          最近更新 更多