本文介紹了在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)
}
提供一個與系統默認設置進行交互的編程接口,用於保存,恢復應用的偏好設置,配置數據等等。
將數據對象存儲到“默認系統”的地方,能夠持久化。
是一個單例。
適合存儲輕量級的存儲數據。
@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裡面可以給定一些特定類型的控件,並設置相應的鍵值對。(如果沒有給出鍵值就不會顯示。)(右鍵可以選擇顯示鍵值對。)
特別值得注意的是,在Text控件裡面可以改為Child Pane
。這是一個子視圖入口,需要在Settings bundle裡面創建另一個plist
。直接創建是創建不了的,只能進入文件夾內部進行操作。(如下圖)然後在File屬性裡面給出相應的文件名就可以訪問了。
//
// 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()
}
}
這就類似於在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是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()
}