簡單理解就是資源文件包,會將許多圖片、xib、文本文件組織在一塊兒,打包成一個 Bundle 文件,這樣能夠在其餘項目中引用包內的資源。sql
// 獲取當前項目的Bundle
let bundle = Bundle.main
// 加載資源
let mp3 = Bundle.main.path(forResource: "xxx", ofType: "mp3")
複製代碼
每個 App 只能在本身的建立的文件系統(存儲區域)中進行文件的操做,不能訪問其餘 App 的文件系統(存儲區域),該文件系統(存儲區域)被成爲沙盒。全部的非代碼文件都要保存在此,例如圖像,圖標,聲音,plist,文本文件等。數據庫
沙盒機制保證了 App 的安全性,由於只能訪問本身沙盒文件下的文件。swift
沙盒的主目錄,能夠經過它查看沙盒目錄的總體結構。跨域
// 獲取程序的Home目錄
let homeDirectory = NSHomeDirectory()
複製代碼
保存應用程序運行時生成的持久化數據。可被iTunes備份,可備份到 iCloud。數組
// 方法1
let documentPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentPath = documentPaths[0]
// 方法2
let documentPath2 = NSHomeDirectory() + "/Documents"
複製代碼
上面的獲取方式最後獲得的是String
,若是但願獲取的是URL
,能夠經過下面的方式:緩存
let manager = FileManager.default
let urlForDocument = manager.urls(for: .documentDirectory, in:.userDomainMask)
let url: URL = urlForDocument[0]
複製代碼
func NSSearchPathForDirectoriesInDomains( _ directory: FileManager.SearchPathDirectory, _ domainMask: FileManager.SearchPathDomainMask, _ expandTilde: Bool) -> [String]
複製代碼
let documentPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, false)
let documentPath = documentPaths[0] // ~/Documents
let documentPaths2 = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentPath2 = documentPaths2[0] // /Users/yangfan/Library/Developer/XCPGDevices/982B6CBA-747B-4831-9D87-F82160197333/data/Containers/Data/Application/56C657D5-B36B-449D-AC6C-E2417EA65D00/Documents
複製代碼
存儲程序的默認設置和其餘信息,其下有兩個重要目錄:安全
UserDefaults
類來取得和設置應用程序的偏好。// Library目錄-方法1
let libraryPaths = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)
let libraryPath = libraryPaths[0]
// Library目錄-方法2
let libraryPath2 = NSHomeDirectory() + "/Library"
// Cache目錄-方法1
let cachePaths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)
let cachePath = cachePaths[0]
// Cache目錄-方法2
let cachePath2 = NSHomeDirectory() + "/Library/Caches"
複製代碼
// 方法1
let tmpDir = NSTemporaryDirectory()
// 方法2
let tmpDir2 = NSHomeDirectory() + "/tmp"
複製代碼
每次編譯代碼會生成新的沙盒路徑,因此模擬器運行同一個 App 時所獲得的沙盒路徑是不同的,但上架的 App 在真機上運行不存在這種狀況。markdown
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 獲取本地plist
let path = Bundle.main.path(forResource: "cityData", ofType: "plist")
if let path = path {
let root = NSDictionary(contentsOfFile: path) // 藉助於NSDictionary
// print(root!.allKeys)
// print(root!.allKeys[31])
// 獲取全部數據
let cities = root![root!.allKeys[31]] as! NSArray // 藉助於NSArray
// print(cities)
// 沙盒路徑
let documentDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let filePath = documentDir! + "/localData.plist"
// 寫入沙盒
cities.write(toFile: filePath, atomically: true)
}
}
}
複製代碼
UserDefaults
來設置和讀取偏好設置。key-value
的方式進行讀寫操做。plist
形式存儲在沙盒的Library/Preferences
目錄。class ViewController: UIViewController {
@IBOutlet weak var username: UITextField!
@IBOutlet weak var password: UITextField!
@IBOutlet weak var swit: UISwitch!
// UserDefaults
let userDefaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
// 取出存儲的數據
let name = userDefaults.string(forKey: "name")
let pwd = userDefaults.string(forKey: "pwd")
let isOn = userDefaults.standard.bool(forKey: "isOn")
// 填充輸入框
username.text = name
password.text = pwd
// 設置開關狀態
swit.isOn = isOn
}
@IBAction func login(_ sender: Any) {
print("密碼已經記住")
}
@IBAction func remember(_ sender: Any) {
let swit = sender as! UISwitch
// 若是記住密碼開關打開
if swit.isOn {
let name = username.text
let pwd = password.text
// 存儲用戶名和密碼
userDefaults.set(name, forKey: "name")
userDefaults.set(pwd, forKey: "pwd")
// 同時存儲開關的狀態
userDefaults.set(swit.isOn, forKey: "isOn")
// 最後進行同步
userDefaults.synchronize()
}
}
}
複製代碼
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
// 當前版本號
var currentVersion: Double!
// UserDefaults
let userDefaults = UserDefaults.standard
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
if isNewVersion {
// 新特性界面
let newVC = UIViewController()
newVC.view.backgroundColor = .green
window?.rootViewController = newVC
// 存儲當前版本號
userDefaults.set(currentVersion, forKey: "localVersion")
userDefaults.synchronize()
} else {
// 主界面
let mainVC = UIViewController()
mainVC.view.backgroundColor = .red
window?.rootViewController = mainVC
}
window?.makeKeyAndVisible()
}
}
extension SceneDelegate {
// 是否新版本
private var isNewVersion: Bool {
// 獲取當前版本號
currentVersion = Double(Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String)!
// 本地版本號
let localVersion = userDefaults.double(forKey: "localVersion")
// 比較大小
return currentVersion > localVersion
}
}
複製代碼
若是須要在使用時設置 UserDefaults 的默認值,可使用register
方法。session
enum Keys: String {
case name // 名字
case isRem // 記住密碼
}
// 設置默認值
UserDefaults.standard.register(defaults: [
Keys.name.rawValue: "UserA",
Keys.isRem.rawValue: false
])
複製代碼
注意:在設置默認值後若是修改了其中的屬性值,即便再次執行
register
方法也不會重置。app
通常狀況下使用UserDefaults.standard
沒有太大問題,但當 App 足夠複雜時就會產生幾個問題:
所以還有另一種獲取 UserDefaults 對象的方法:UserDefaults(suiteName: String?)
,能夠根據傳入的 suiteName 參數進行處理:
UserDefaults.standard
。Documents/Library/Preferences
目錄下以suiteName
命名的 plist 文件。能夠經過以下的方式刪除指定suiteName
的 plist 文件裏的所有數據。
let userDefaults = UserDefaults(suiteName: "abc")
userDefaults?.removePersistentDomain(forName: "abc")
複製代碼
Data
,反歸檔(反序列化)是從Data
還原出對象。NSObject
並遵循NSSecureCoding
協議。class Person: NSObject, NSSecureCoding {
var name:String?
var age:Int?
override init() {
}
static var supportsSecureCoding: Bool = true
// 編碼- 歸檔調用
func encode(with aCoder: NSCoder) {
aCoder.encode(age, forKey: "age")
aCoder.encode(name, forKey: "name")
}
// 解碼-反歸檔調用
required init?(coder aDecoder: NSCoder) {
super.init()
age = aDecoder.decodeObject(forKey: "age") as? Int
name = aDecoder.decodeObject(forKey: "name") as? String
}
}
複製代碼
class ViewController: UIViewController {
var data: Data!
var origin: Person!
override func viewDidLoad() {
super.viewDidLoad()
}
// 歸檔
@IBAction func archiver(_ sender: Any) {
let p = Person()
p.age = 20
p.name = "zhangsan"
do {
try data = NSKeyedArchiver.archivedData(withRootObject: p, requiringSecureCoding: true)
} catch {
print(error)
}
}
// 反歸檔
@IBAction func unarchiver(_ sender: Any) {
do {
try origin = NSKeyedUnarchiver.unarchivedObject(ofClass: Person.self, from: data)
print(origin!.age!)
print(origin!.name!)
} catch {
print(error)
}
}
}
複製代碼
因爲 Swift 直接操做 sqlite3 很是不方便,因此藉助於SQLite.swift
的框架。
struct Person {
var name : String = ""
var phone : String = ""
var address : String = ""
}
複製代碼
import SQLite
struct DBTools {
// 數據庫路徑
let dbPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/person.db"
// 數據庫鏈接
var db: Connection!
// 表名與字段
let personTable = Table("t_person") // 表名
let personID = Expression<Int>("id") // id
let personName = Expression<String>("name") // name
let personPhone = Expression<String>("phone") // phone
let personAddress = Expression<String>("address") // address
// MARK: - 構造函數,數據庫有則鏈接 沒有就建立後鏈接
init() {
do {
db = try Connection(dbPath)
print("數據庫建立/鏈接成功")
} catch {
print("數據庫建立/鏈接失敗")
}
}
// MARK: - 建立表格,表若存在不會再次建立,直接進入catch
func createTable() {
// 創表
do {
try db.run(personTable.create(block: { t in
t.column(personID, primaryKey: .autoincrement)
t.column(personName)
t.column(personPhone)
t.column(personAddress)
}))
print("數據表建立成功")
} catch {
print("數據表建立失敗")
}
}
// MARK: - 插入數據
func insertPerson(person: Person) {
let insert = personTable.insert(personName <- person.name, personPhone <- person.phone, personAddress <- person.address)
// 插入
do {
try db.run(insert)
print("插入數據成功")
} catch {
print("插入數據失敗")
}
}
// MARK: - 刪除數據
func deletePerson(name: String) {
// 篩選數據
let p = personTable.filter(personName == name)
// 刪除
do {
let row = try db.run(p.delete())
if row == 0 {
print("暫無數據刪除")
} else {
print("數據刪除成功")
}
} catch {
print("刪除數據失敗")
}
}
// MARK: - 更新數據
func updatePerson(person: Person) {
// 篩選數據
let p = personTable.filter(personName == person.name)
// 更新
do {
let row = try db.run(p.update(personPhone <- person.phone, personAddress <- person.address))
if row == 0 {
print("暫無數據更新")
} else {
print("數據更新成功")
}
} catch {
print("數據更新失敗")
}
}
// MARK: - 查詢數據
func selectPerson() -> [Person]? {
// 保存查詢結果
var response: [Person] = []
// 查詢
do {
let select = try db.prepare(personTable)
for person in select {
let p = Person(name: person[personName], phone: person[personPhone], address: person[personAddress])
response.append(p)
}
if !response.isEmpty {
print("數據查詢成功")
} else {
print("對不起,暫無數據")
}
return response
} catch {
print("數據查詢失敗")
return nil
}
}
}
複製代碼
class ViewController: UIViewController {
var dbTools: DBTools?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func createDB(_ sender: Any) {
dbTools = DBTools()
}
@IBAction func createTab(_ sender: Any) {
dbTools?.createTable()
}
@IBAction func insertData(_ sender: Any) {
let p = Person(name: "zhangsan", phone: "18888888888", address: "AnHuiWuhu")
dbTools?.insertPerson(person: p)
}
@IBAction func deleteData(_ sender: Any) {
dbTools?.deletePerson(name: "zhangsan")
}
@IBAction func updateData(_ sender: Any) {
let p = Person(name: "zhangsan", phone: "17777777777", address: "JiangSuNanJing")
dbTools?.updatePerson(person: p)
}
@IBAction func selectData(_ sender: Any) {
let person = dbTools?.selectPerson()
if let person = person {
for p in person {
print(p)
}
}
}
}
複製代碼