你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> [IOS]數據永久化

[IOS]數據永久化

編輯:IOS開發綜合

數據存儲

本文介紹了在IOS中常見的幾種保存數據的方式,以及相關的實現方法(基於swift)。

思維導圖:
Subtitle4copy

應用程序沙盒

每個IOS程序有一套自己獨立的文件系統,其路徑以 / 開始, 這個文件系統成為應用程序沙盒。每個應用程序只能在自己的沙盒內部讀寫文件,基本不可以去訪問外部文件。所有的操作都要進行權限檢測。

沙盒是一種安全機制,其核心是對IOS應用的操作進行權限檢測。
Subtitle6
Subtitle7
Subtitle8

Subtitle10

為什幺要用沙盒?

防止應用被其他應用惡意修改、訪問和刪除。 防止其他軟件訪問你的個人數據。 能夠很干淨地清楚數據。
  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

Subtitle13

在Settings bundle裡面可以給定一些特定類型的控件,並設置相應的鍵值對。(如果沒有給出鍵值就不會顯示。)(右鍵可以選擇顯示鍵值對。)

特別值得注意的是,在Text控件裡面可以改為Child Pane。這是一個子視圖入口,需要在Settings bundle裡面創建另一個plist。直接創建是創建不了的,只能進入文件夾內部進行操作。(如下圖)然後在File屬性裡面給出相應的文件名就可以訪問了。
Subtitle12

訪問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
      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()
  }
}

通用文件存儲

Subtitle2

Subtitle3
Subtitle4
Subtitle5

這就類似於在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()
  }
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved