关于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,点击下载,喜欢的话给颗星哈。。

原创粉丝点击