关于plist文件存储方式(swift)
来源:互联网 发布:仿真软件培训 编辑:程序博客网 时间:2024/05/19 17:47
关于数据持久化操作一直是大家非常关注的问题,我最近看了好多关于数据存储方式的文章,小编在这里写下我的见解,希望能对大家有所帮助!
谈到数据储存,首先要明确区分两个概念,数据结构和储存方式。所谓数据结构就是数据存在的形式。除了基本的Dictionary、Array和Set这些对象,还有更复杂的如:关系模型、对象图和属性列表多种结构。而存储方式则简单的分为两种:内存与闪存。内存存储是临时的,运行时有效的,但效率高,而闪存则是一种持久化存储,但产生I/O消耗,效率相对低。把内存数据转移到闪存中进行持久化的操作称成为归档。
目前数据存储方式大致上可以归纳为以下几种:
1、UserDefaults;这种存储方式非常常用,它操作方便,这是系统给的一个单例类,直接操作沙盒中的Library中的Preferences中的一个名为本应用的BundleID的plist文件。但是它只适合存储用户的一些偏好设置,不易存储大量数据,它在软件升级后不会被删除。
2、writeToFile写入;该方法是一次性向文件中写入内容,本次写入会覆盖文件中原来的内容,所以适合存储经常不易变动的数据文件,可以配合plist文件使用。
3、NSCoding归档;它跟其他存储方式略有不同,他可以存储对象,能把任何对象都直接保存成文件的方式来存储,但该对象必须遵循NSCoding协议,NSKeyedArchiver存储,NSKeyedUnarchiver读取,由于它可以直接对对象进行存储,所以也很常用,比较受大家喜欢。
4、SQLite3数据库;这种方法最实用但是操作也最麻烦,于是GitHub上就出现了好多关于对SQLite3的封装,其中评星最高的有FMDB(OC)、SQLite.Swift(Swift),这两种我都试着用了一下,感觉还是有点儿麻烦,后来也对这两个库进行了2次封装,凑合着用了,这里我不是专门说它,就不拿出来献丑了,我想好多人对数据库操作不是很了解,关于对数据库的操作,我推荐看它:http://www.runoob.com/sqlite/sqlite-create-table.html。
5、Core Data(苹果官方推荐);它其实是对SQLite3的封装,哈哈,苹果也感觉直接使用SQLite3过于麻烦,于是乎…就出现了Core Data,它更加面向对象,苹果强烈推荐使用,但是每次总是需要建好多的文件,可我不习惯,看个人喜好了。
6、Realm;这是什么鬼,据说它有志于替代SQLite数据库,不过我还没仔细研究过,只是在网上看到过,评价还挺高,怎么用不清楚,但是我想不会比SQLite3操作更麻烦了,附上GitHub上地址。
好了,说了这么多,该回到正题了,今天我主要是说plist,全名PropertyList,即属性列表文件,它是一种用来存储串行化后的对象的文件。这种文件,在ios开发过程中经常被用到。这种属性列表文件的扩展名为.plist,因此通常被叫做plist文件。plist文件用source code方式打开,它其实是xml格式的。Plist文件是以key-value的形式来存储数据。既可以用来存储用户设置,也可以用来存储一些需要经常用到而不经常改动的信息。
plist存储方式操作简单,但是只适合存储小数据,像哪些以M为单位的数据就不易用这种方法了,因为它有个很大的缺点,在上面我也说到了:它每次写入都会覆盖文件中原来的内容。也就是说,每次你都需要先把文件里面的内容全部读取出来先放到内存中,然后修改好root dictionary里的内容之后再写入进去,你说是不是很鸡肋,如果你存储了几十M的东西,这样一下子写来写去的,你内存吃的消吗,况且这么大的数据读取和写入多耗时间啊。纵是如此我还是很喜欢用这种方式,小的数据没问题啊···
下面呢,我专门写了一个类来管理plist文件的操作,使用很简单,给大家分享一下:
import UIKitpublic enum Type :Int{ case number case string case bool case array case dictionary case null case unknown case data}class PlistManager: NSObject { private override init() { super.init() } static let defaltManager = PlistManager() private let path = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0] /** 读取根目录 plistName:plist文件名 **/ subscript (_ plistName:String) -> Dictionary<String,Any> { get { let filePath = "\(path)/MyDatas/\(plistName).plist" if FileManager.default.fileExists(atPath: filePath) { let rootDic = NSDictionary.init(contentsOfFile: filePath) return rootDic as! Dictionary<String, Any> } return Dictionary<String,Any>() } } /** 读取数据 plistName:文件名,name:字段名 **/ subscript (_ plistName:String,_ name:String) -> JHJSON { get { let filePath = "\(path)/MyDatas/\(plistName).plist" if FileManager.default.fileExists(atPath: filePath) { let rootDic = NSDictionary.init(contentsOfFile: filePath) return JHJSON.init(rootDic![name]) } return JHJSON.init(nil) } } /** 写入数据 **/ func set(value:Any,forKey:String,plistName:String) { if forKey == "" || plistName == ""{ return } let filePath = "\(path)/MyDatas/\(plistName).plist" print("plist文件路径 === \(filePath)") if !(FileManager.default.fileExists(atPath: filePath)) { if let dict = value as? Dictionary<String,Any> { //如果存储对象是字典就转化为json字符串,防止字典内存在空值导致写入plist失败 let dic = [forKey:dict.toJsonString()] as NSDictionary dic.write(toFile: filePath, atomically: true) }else{ let dic = [forKey:value] as NSDictionary dic.write(toFile: filePath, atomically: true) } }else{ if let dict = value as? Dictionary<String,Any> { //如果存储对象是字典就转化为json字符串,防止字典内存在空值导致写入plist失败 var dic = self[plistName] dic[forKey] = dict.toJsonString() (dic as NSDictionary).write(toFile: filePath, atomically: true) }else{ var dic = self[plistName] dic[forKey] = value (dic as NSDictionary).write(toFile: filePath, atomically: true) } } }}/** 用来解析数据 **/struct JHJSON { fileprivate var rawArray: [Any]! fileprivate var rawDictionary: [String : Any]! fileprivate var rawString: String! fileprivate var rawNumber: NSNumber! fileprivate var rawNull: NSNull = NSNull() fileprivate var rawBool: Bool = false fileprivate var rawData : Data! fileprivate var type: Type = .null public init(_ object: Any?) { if object != nil { switch object { case let object as [Any] where object.count > 0: self.rawArray = object as [Any] self.type = .array break case let object as Dictionary<String,Any> where object.count > 0: self.rawDictionary = object self.type = .dictionary break case let object as String: self.rawString = object self.type = .string break case let object as NSNumber: self.rawNumber = object self.type = .number break case let object as Bool: self.rawBool = object self.type = .bool break case let object as Data: self.rawData = object self.type = .data break default: self.type = .null break } } } /** 转化为String **/ public var stringValue: String { get { switch self.type { case .string: return self.rawString ?? "" case .number: return self.rawNumber.stringValue case .bool: return self.rawBool == true ? "1" : "0" case .data: return String.init(data: self.rawData, encoding: .utf8)! default: return "" } } } /** 转化为Array **/ public var arrayValue: [Any] { get { switch self.type { case .array: return self.rawArray default: return [Any]() } } } /** 转化为Dictionary **/ public var dictionaryValue: Dictionary<String,Any> { get { switch self.type { case .dictionary: return self.rawDictionary case .data: do { let json = try JSONSerialization.jsonObject(with: self.rawData, options: .mutableContainers) if let dic = json as? Dictionary<String,Any> { return dic }else { print("不是正确的字典格式") return Dictionary<String,Any>() } } catch { print("不是正确的字典格式:\(error.localizedDescription)") return Dictionary<String,Any>() } case .string: let jsonData:Data = self.rawString.data(using: .utf8)! do { let json = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) if let dict = json as? Dictionary<String,Any> { return dict }else { print("不是正确的字典格式") return Dictionary<String,Any>() } } catch { print("不是正确的字典格式:\(error)") return Dictionary<String,Any>() } default: print("不是正确的字典格式") return Dictionary<String,Any>() } } } /** 转化为NSNumber **/ public var numberValue: NSNumber { get { switch self.type { case .string: let decimal = NSDecimalNumber(string: self.rawString) if decimal == NSDecimalNumber.notANumber { // indicates parse error return NSDecimalNumber.zero } return decimal case .number: return self.rawNumber ?? NSNumber(value: 0) case .bool: return NSNumber(value: self.rawBool ? 1 : 0) default: return NSNumber(value: 0.0) } } } /** 转化为Bool **/ public var boolValue: Bool { get { switch self.type { case .bool: return self.rawBool case .number: return self.rawNumber.boolValue case .string: return ["true", "y", "t"].contains() { (truthyString) in return self.rawString.caseInsensitiveCompare(truthyString) == .orderedSame } default: return false } } } /** 转data **/ public var dataValue: Data { get { switch self.type { case .data: return self.rawData default: return Data.init() } } }}
使用方法:
PlistManager.defaltManager.set(value: 2, forKey: "id", plistName: "MyPlis")//写入print(PlistManager.defaltManager["MyPlis"])//读取root dictionaryprint(PlistManager.defaltManager["MyPlis","data"].dictionaryValue)//根据字段读取
源文件已分享到github,点击下载,喜欢的话给颗星哈。。
- 关于plist文件存储方式(swift)
- Swift - .plist文件数据的读取和存储
- Swift plist文件读写
- swift plist文件
- iOS-数据存储方式一之plist文件存储
- plist文件存储
- 关于swift中的plist文件的写入用来存储信息,例如登录的时候出入信息,这里给一个完成的代码
- 关于plist文件路径的两种读写方式
- 关于plist文件
- 存储方式一----------------plist的存储
- ios应用数据存储方式(plist存储)
- IOS-Plist文件存储(1)
- 使用plist文件存储信息
- ios plist文件存储数据
- swift读取本地数据元 *.plist 文件
- Swift读写plist文件教程及代码
- swift Plist文件的读写
- iOS 数据存储 plist文件存储
- XML的声明
- unity优化篇
- poj_2115-C Looooops
- 深入理解Spark 2.1 Core (十三):sparkEnv类源码分析
- 文字如何与单选框垂直对齐
- 关于plist文件存储方式(swift)
- V4L2 获取和配置摄像头程序示例(使用v4l2_queryctrl )
- 探索skynet(二):skynet如何启动一个服务
- Spring Security(07)——缓存UserDetails
- Unity Shader:三向贴图(Tri-planar mapping)---解决地形拉伸贴图变形以及贴图边缘的缝隙问题
- git删除远程分支文件
- 在ARM实验板LCD上显示汉字
- 安卓自定义饼状图
- [LeetCode] 104. Maximum Depth of Binary Tree