[IOS]数据永久化

数据存储

本文介绍了在IOS中常见的几种保存数据的方式,以及相关的实现方法(基于swift)。

思维导图:

应用程序沙盒

每个IOS程序有一套自己独立的文件系统,其路径以 / 开始, 这个文件系统成为应用程序沙盒。每个应用程序只能在自己的沙盒内部读写文件,基本不可以去访问外部文件。所有的操作都要进行权限检测。

沙盒是一种安全机制,其核心是对IOS应用的操作进行权限检测。

为什幺要用沙盒?

  • 防止应用被其他应用恶意修改、访问和删除。
  • 防止其他软件访问你的个人数据。
  • 能够很干净地清楚数据。
  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    // In Unix, ~ -> /User/User name/...

    // fetch document file address.
    var paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, false)
    let doucmentDirectory = paths[0] as String
    print(doucmentDirectory)

    var tempDirectory = NSTemporaryDirectory()

    // manager file.
    let fileManager = NSFileManager.defaultManager()
    let DoucementDirectoryWithManager = fileManager.URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask)
    print(DoucementDirectoryWithManager)
  }

NSUserDefaults

提供一个与系统默认设置进行交互的编程接口,用于保存,恢复应用的偏好设置,配置数据等等。

将数据对象存储到“默认系统”的地方,能够持久化。

是一个单例。

适合存储轻量级的存储数据。

可以存储的数据类型

  • NSData
  • NSNumber
  • NSString
  • NSDate
  • NSArray
  • NSDictionary
  • Bool

示例

  @IBOutlet weak var TextField: UITextField!
  // The unique object!
  var Users = NSUserDefaults.standardUserDefaults()
  @IBAction func DataSave(sender: UIButton) {
    let text = TextField.text
    // Just the database, with value-to-key, it can set the data.
    // Each key is unique.
    Users.setObject(text, forKey: "Text")
    // Don‘t forget to sync!
    Users.synchronize()
  }

  @IBAction func DataLoad(sender: UIButton) {
    // get string value.
    let text = Users.stringForKey("Text")
    TextField.text = text
  }

Settings Bundle

在自己的应用中建立的一组文件,利用它可以告诉设备中的“设置”应用。(特别是在偏好设置)

plist file

在Settings bundle里面可以给定一些特定类型的控件,并设置相应的键值对。(如果没有给出键值就不会显示。)(右键可以选择显示键值对。)

特别值得注意的是,在Text控件里面可以改为Child Pane。这是一个子视图入口,需要在Settings bundle里面创建另一个plist。直接创建是创建不了的,只能进入文件夹内部进行操作。(如下图)然后在File属性里面给出相应的文件名就可以访问了。

访问Settings

//
//  ViewController.swift
//  数据持久化
//
//  Created by 颜泽鑫 on 7/7/16.
//  Copyright ? 2016 颜泽鑫. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    // loadDefaults()
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
    //    getUserDefaults()
  }
  @IBOutlet weak var TextField: UITextField!
  // The unique object!
  var Users = NSUserDefaults.standardUserDefaults()
  @IBAction func DataSave(sender: UIButton) {
    updateUserDefaults()
  }
  @IBAction func DataLoad(sender: UIButton) {
    getUserDefaults()
  }
  /**
   Load Settings.bundles information and put them into NSUserDefaults.
   */
  func loadDefaults() {
    /// Enter the Settings.bundle.
    let SettingsBubble = NSBundle.mainBundle().pathForResource("Settings", ofType: "bundle")
    if SettingsBubble == nil {
      return
    } else {
      // enter the More plist file.
      // pay attention to `/`.
      // stringByAppendingString : append another stirng.
      // the valid URL gap by `/`.
      // in this file, the data is save as dictionary.
      let root = NSDictionary(contentsOfFile: SettingsBubble!.stringByAppendingString("/More.plist"))
      //  By key, you can get the whole Array,
      let preferences = root?.objectForKey("PreferenceSpecifiers") as! Array<NSDictionary>
      let defaultToRegister = NSMutableDictionary(capacity: root!.count)
      // visit the whole array, and put them together into `defaultToRegister`.
      for preference in preferences {
        let key = preference.objectForKey("Key") as! String?
        if key != nil {
          defaultToRegister.setValue(preference.objectForKey("DefaultValue"), forKey: key!)
        }
      }
      // put the `defaultToRegister` into NSUserDefaults so that they can be load.
      NSUserDefaults.standardUserDefaults().registerDefaults((defaultToRegister as NSDictionary) as! [String : AnyObject])
    }
  }
  func getUserDefaults() {
    // Because of having load info, you can easy get value by its key.
    let Defaults = NSUserDefaults.standardUserDefaults()
    TextField.text = Defaults.objectForKey("name_preferences") as? String
  }

  func updateUserDefaults() {
    let Defaults = NSUserDefaults.standardUserDefaults()
    Defaults.setBool(false, forKey: "enabled_preference")
    // Don‘t forget to sync.
    Users.synchronize()
  }
}

通用文件存储

这就类似于在C中做文件操作,只能完全地读入文件内信息,对于类似于Database的信息,仍然需要做特别的转换。(可以使用json文件,目前还没有找到合适的json库。)

示例:

  @IBOutlet weak var TextField: UITextField!
  // The unique object!
  var Users = NSUserDefaults.standardUserDefaults()
  @IBAction func DataSave(sender: UIButton) {
    let text = TextField.text! as NSString
    /**
     *  Write the info into file.
     *  Using error handling, too.
     */
    do {
      try text.writeToFile(getFilePath("data.txt"), atomically: true, encoding: NSUTF8StringEncoding)
    } catch {
      print("Can‘t save!")
      return
    }
  }

  @IBAction func DataLoad(sender: UIButton) {
    let textFilePath = getFilePath("data.txt")
    //  Judge if the file exists.
    if NSFileManager.defaultManager().fileExistsAtPath(textFilePath) {
      /**
       *  Transfer the file info to NSString is `throws` functions.
       *  So it is neccessary to use error handling method.
       */
      do {
        let text = try NSString(contentsOfFile: textFilePath, encoding: NSUTF8StringEncoding)
        TextField.text = text as String
      } catch {
        print("Can‘t load!")
      }
    } else {
      print("File don‘t exist!")
    }
  }
  /**
   In this function, we will get the path of file.

   - parameter filename: The file name you wanna load.

   - returns: path
   */
  func getFilePath(filename : String) -> String {
    let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
    var DocumentPath = path[0] as NSString
    /**
     *  You still need to pay attention to add `/` before file name.
     *  So that you can interval the different component.
     *  @param "/"
     *
     *  @return path
     */
    DocumentPath = DocumentPath.stringByAppendingString("/")
    return DocumentPath.stringByAppendingString(filename)
  }

对象模型归档

用于存储一些在通用文件保存中无法保存的类型,例如图片、视频等等

两个关键概念:

  • 对象归档(Archive): 将对象转换成一种可以写入文件的格式,通常是以一种不可读的方式进行保存。
  • 对象反归档(Unarchive):将数据从文件中读出并自动重建对象。

示例

import Foundation
import UIKit
/// This is the data type which we wanna save.
class Person : NSObject, NSCoding {
  var name = ""
  var logos : UIImage!

  override init() {
     super.init()
  }
  /**
   This method is neccessary which is used to get info
   from the file.
   */
  required init?(coder aDecoder: NSCoder) {
    super.init()
    name = aDecoder.decodeObjectForKey("name") as! String
    logos = aDecoder.decodeObjectForKey("logo") as! UIImage
  }
  /**
   This method is used to input info into the file.
   */
  func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(name, forKey: "name")
    aCoder.encodeObject(logos, forKey: "logo")
  }
}
//
//  ViewController.swift
//  数据持久化
//
//  Created by 颜泽鑫 on 7/7/16.
//  Copyright ? 2016 颜泽鑫. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    // loadDefaults()

  }
  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
    //    getUserDefaults()
  }

  @IBOutlet weak var TextField: UITextField!
  // The unique object!
  @IBOutlet weak var logo: UIImageView!

  @IBAction func DataSave(sender: UIButton) {
    let text = TextField.text!
    let logos = UIImage(named: "1")
    let textPath = getFilePath("data.txt")
    let person = Person()
    person.name = text
    person.logos = logos
    /// Archive the `person` and then write it into the file.
    let data = NSKeyedArchiver.archivedDataWithRootObject(person)
    do {
      try data.writeToFile(textPath, options: NSDataWritingOptions.AtomicWrite)
    } catch {
      print("Write error!")
    }
  }

  @IBAction func DataLoad(sender: UIButton) {
    let textPath = getFilePath("data.txt")
    /// Unarchive the file to get `Person` info.
    let person = NSKeyedUnarchiver.unarchiveObjectWithFile(textPath) as! Person
    TextField.text = person.name
    logo.image = person.logos
  }
  /**
   In this function, we will get the path of file.

   - parameter filename: The file name you wanna load.

   - returns: path
   */
  func getFilePath(filename : String) -> String {
    let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
    var DocumentPath = path[0] as NSString
    /**
     *  You still need to pay attention to add `/` before file name.
     *  So that you can interval the different component.
     *  @param "/"
     *
     *  @return path
     */
    DocumentPath = DocumentPath.stringByAppendingString("/")
    return DocumentPath.stringByAppendingString(filename)
  }
}

Core Data

Core Data是IOS对关系型数据库的一种封装,类似于编写Database一样保存数据。但是缺点是,相对比较麻烦,除非数据非常大,否则尽量不使用。

//
//  ViewController.swift
//  core
//
//  Created by 颜泽鑫 on 7/8/16.
//  Copyright ? 2016 颜泽鑫. All rights reserved.
//

import UIKit
import CoreData
class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    /// Get AppDelegate object.
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    /// Get context which save the info of Company.
    let context = appDelegate.managedObjectContext
    /// This Request can execute all operation like, update, save or read.
    let companyRequest = NSFetchRequest(entityName: "Company")
    do {
      let companyObjects = try context.executeFetchRequest(companyRequest) as! [NSManagedObject]
      for object in companyObjects {
        let name = object.valueForKey("name") as! String
        let age = object.valueForKey("age") as! Int
        let area = object.valueForKey("area") as! String
        print("load Data name : \(name)")
        print("load Data age : \(age)")
        print("load Data area : \(area)")
      }
    } catch {
      print("Fetch error!")
    }
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
}

AppDelegate里面还保存了很多相关的操作,可以仔细阅读相关注释。

// in AppDelegate
  func applicationWillTerminate(application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    // Saves changes in the application‘s managed object context before the application terminates.
    let name = "stary"
    let age = 20
    let area = "ShenZhen"
    let companyRequest = NSFetchRequest(entityName: "Company")
    do {
      let companyObjects = try managedObjectContext.executeFetchRequest(companyRequest) as! [NSManagedObject]

      var Company : NSManagedObject?
      /**
       *  Judge if there is Company object.
       *  If there isn‘t one, then you can initialize a new one.
       */
      if companyObjects.count > 0 {
        Company = companyObjects[0]
      } else {
        Company = NSEntityDescription.insertNewObjectForEntityForName("Company", inManagedObjectContext: managedObjectContext) as NSManagedObject
      }
      Company?.setValue(name, forKey: "name")
      Company?.setValue(age, forKey: "age")
      Company?.setValue(area, forKey: "area")
    } catch {
      print("Save error!")
    }
    self.saveContext()
  }
时间: 2024-12-19 10:55:16

[IOS]数据永久化的相关文章

[C++]关于数据永久化的思考(不使用数据库)

关于数据永久化的思考(不使用数据库) ==数据永久化==是一个程序很重要的特性.我们知道使用数据库肯定可以实现数据永久化,但对于新手而言,比较艰难.本文讨论的是,如何不使用数据库来完成数据的保存.主要提供两种方法,一种是使用纯粹的文件读写,另一种使用json.首先,我们先来复习一下文件操作的基本信息. C++文件操作 文件指存放在外部介质上的数据的集合.大家都知道操作系统是以文件为单位来对数据进行管理的.因此如果你要查找外部介质的数据,则先要按文件名找到指定文件,然后再从文件中读取数据,如果要把

iOS数据持久化存储

本文中的代码托管在github上:https://github.com/WindyShade/DataSaveMethods 相对复杂的App仅靠内存的数据肯定无法满足,数据写磁盘作持久化存储是几乎每个客户端软件都需要做的.简单如"是否第一次打开"的BOOL值,大到游戏的进度和状态等数据,都需要进行本地持久化存储.这些数据的存储本质上就是写磁盘存文件,原始一点可以用iOS本身支持有NSFileManager这样的API,或者干脆C语言fwrite/fread,Cocoa Touch本身

iOS数据存储的几种方式

iOS的数据存储是iOS应用开发的重要知识点: 关于这方面知识,网上有很多介绍,但对于代码层次的使用方式并未有系统全面介绍.此文章针对iOS稍熟悉的童鞋,需要对CoreData的原理有一定的了解.目前存储方式大概有以下几种: NSKeyedArchiver  适用简单数据加密 NSUserDefaults  适用配置参数 Write  文件操作,同NSKeyedArchiver SQLite3  操作较复杂,不建议使用. CoreData  取代SQLite3,但要遵循NSManagedObje

IOS数据持久化之归档NSKeyedArchiver

IOS数据持久化的方式分为三种: 属性列表 (自定义的Property List .NSUserDefaults) 归档 (NSKeyedArchiver) 数据库 (SQLite.Core Data.第三方类库等) 下面主要来介绍一个归档NSKeyedArchiver. 归档(又名序列化),把对象转为字节码,以文件的形式存储到磁盘上:程序运行过程中或者当再次重写打开程序的时候,可以通过解归档(反序列化)还原这些对象. 归档方式: 对Foundation框架中对象进行归档 对自定义的内容进行归档

iOS数据存储之CoreData

iOS中大量数据的储存一个是SqLite,另一个就是CoreData,CoreData允许程序员以面向对象的思维方式的方法去操作面向表的数据库 做过Java开发的对这个应该很熟悉,Java中的Hibernate跟CoreData就很相似 CoreData应该怎样使用呢? 第一步,新建工程后导入CoreData框架 第二部,创建CoreData的数据模型创建步骤如下 然后给你的model起个名字,创建完成后你会看到一个这个文件(相当于数据库文件) 点击这个文件,然后看下图 点击图中1,新建实体(类

IOS数据存储 —— 2 存储方式

IOS数据存储方式 iOS开发常用数据存储方式有:plist.偏好设置 NSUserDefaults.对象归档 NSKeyedArchiver.SQLite3和Core Data 1. plist文件 存储 plist文件通常用于储存用户设置,利用xml属性列表归档NSDictionary.NSArray.NSNumber等类型数据 在使用plist进行数据存储和读取,只适用于系统自带的一些常用类型才能用 注意:plist不能存储自定义对象 2. 偏好设置 NSUserDefaults 偏好设置

IOS数据本地存储的四种方式--

注:借鉴于:http://blog.csdn.net/jianjianyuer/article/details/8556024 在IOS开发过程中,不管是做什么应用,都会碰到数据保存问题.将数据保存到本地,能够让程序更加流畅,不会出现让人厌恶的菊花状,使得用户的体验更好.下面是介绍数据保存的方式 第一.NSKeyedArchiver:采用归档的形式来保存数据.(归档——解档)———大量数据和频繁读写不合适使用 1.归档器的作用是将任意的对象集合转换为字节流.这听起来像是NSPropertyLis

iOS数据存储之SqLite3

iOS中数据存储的方式有很多中,当数据量较大的时候偏好设置,归档和plist就无法满足需求了 这时候就需要用SqLite或者CoreData来存储数据 下面就来介绍一下如何使用SqLite存储数据 要使用Sqlite必须引入libSqlite3.dylib库 要使用首先要有一个handle句柄(handle句柄,在C语言中,通常把用于控制某类东西的叫做句柄,实际上是一个指针.) // 数据库句柄 sqlite3 *_db; SqLite存储数据时也是存在一个文件中的,只不过这个文件格式是定制的,

iOS数据持久化方式分析

iOS数据持久化的方式一般为:plist文件写入.对象归档.SQLite数据库.CoreData. plist文件写入.对象归档一般用于小的数据量. SQLite数据库.CoreData则用于大的数据量. SQLite是一款轻型的数据库,是一种关系型数据库管理系统,他的设计目的是嵌入式设备中使用. SQLite占用资源非常低,非常适合移动设备中使用,而且是开源免费的 SQLite的数据库操作其实和常规的数据库操作流程是一样的: 1.打开数据库 sqlite3_open() 2.准备SQL语句,采