Post on 26-Jun-2018
transcript
Data StorageMobile Application Development in iOS
School of EECS
Washington State University
Instructor: Larry Holder
Mobile Application Development in iOS 1
Data Storage
• Already seen: UserDefaults, iCloud
• File I/O
• Database support: CoreData, SQLite
• Data backup to iCloud
• Data protection
Mobile Application Development in iOS 2
File I/O
• FileManager
– .default: shared file manager for app
– Numerous methods for manipulating files
• FileManagerDelegate
– Constraint checking and error handling
Mobile Application Development in iOS 3
File I/O
• Get URL to directory
• Append file name to URL
• Convert data to String
• Use String.write(to: URL, encoding: .utf8) to write
• Use String(contentsOf: URL , encoding: .utf8) to read
• Both throw errors
Mobile Application Development in iOS 4
File I/O: Write
Mobile Application Development in iOS 5
let fileName = "myDataFile"
func writeData(_ str: String) -> Bool {if let directoryURL = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask).first {let fileURL = directoryURL.appendingPathComponent(fileName)do {
try str.write(to: fileURL, atomically: true, encoding: .utf8)return true
} catch {print("\(error)")
}}return false
}
File I/O: Read
Mobile Application Development in iOS 6
func readData() -> String? {if let directoryURL = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask).first {let fileURL = directoryURL.appendingPathComponent(fileName)do {
let str = try String(contentsOf: fileURL, encoding: .utf8)return str
} catch {print("\(error)")
}} else {
print("Error accessing document directory.")}return nil
}
File I/O: Codable
Problem: Convert everything to a • String
Solu:on: • Codable (new in Swi= 4)
Can be encoded/decoded to common formats, e.g., JSON–
JSON data easily converted to/from – String
All basic types and containers are • Codable
Classes consis:ng of • Codable proper:es are Codable
Mobile Application Development in iOS 7
File I/O: Codable
Mobile Application Development in iOS 8
class Player: Codable {var name: Stringvar health: Int
init(_ name: String, _ health: Int) {self.name = nameself.health = health
}}
File I/O: Codable
Mobile Applica3on Development in iOS 9
func writePlayer(_ player: Player) -> Bool {let jsonEncoder = JSONEncoder()do {
let jsonData = try jsonEncoder.encode(player)if let jsonStr = String(data: jsonData, encoding: .utf8) {
if writeData(jsonStr) {return true
}}
} catch {print("\(error)")
}return false
}
File I/O: Codable
Mobile Application Development in iOS 10
func readPlayer() -> Player? {if let str = readData() {
if let jsonData = str.data(using: .utf8) {let jsonDecoder = JSONDecoder()do {
let player = try jsonDecoder.decode(Player.self,from: jsonData)
return player} catch {
print("\(error)")}
}}return nil
}
Database SupportCore Data•
iOS specific object store–
SQLite (• www.sqlite.org)
Cross– -pla=orm table store (already available in iOS)
Third• -party opEons
Realm (– realm.io) Cross• -pla=orm object store
Couchbase Lite (– www.couchbase.com/products/lite) Cross pla=orm document store (NoSQL)•
Firebase (– firebase.google.com) Cross• -pla=orm document store (NoSQL)
Mobile Application Development in iOS 11
Core Data
• Check “Use Core Data”
for New Project
• Includes empty data
model
• Includes boilerplate
code to create database
Mobile Application Development in iOS 12
Core Data: Model
Create Managed Object Model (Schema)•
Schema consists of • en;;es, their a=ributes,
and rela;onships
Mobile Application Development in iOS 13
Core Data: Stack
• Handles interactions with data store
– Persistent container (NSPersistentContainer)
• Obtained from UIApplication.shared.delegate
– Managed object context (NSManagedObjectContext)
• Obtained from NSPersistentContainer.viewContext
Mobile Application Development in iOS 14
Core Data: Insert
Methods•
NSEn3tyDescrip3on– .insertNewObject(forEn3tyName:
String, into: NSManagedObjectContext) ->
NSManagedObject
NSManagedObject– .setValue(value: Any?, forKey: String)
NSManagedObjectContext– .save()
Mobile Application Development in iOS 15
Core Data: Insert
Mobile Application Development in iOS 16
import CoreData
class ViewController: UIViewController {
var managedObjectContext: NSManagedObjectContext!var appDelegate: AppDelegate!
override func viewDidLoad() {super.viewDidLoad()self.appDelegate = UIApplication.shared.delegate as! AppDelegateself.managedObjectContext =
appDelegate.persistentContainer.viewContext}
func addPlayer() {let player = NSEntityDescription.insertNewObject(forEntityName:
"Player", into: self.managedObjectContext)player.setValue("Mario", forKey: "name")player.setValue(100, forKey: "health")self.appDelegate.saveContext() // In AppDelegate.swift
}}
Core Data: Fetch
Methods•
NSFetchRequest– <NSManagedObject>(en=tyName:
String) -> NSFetchRequest<NSManagedObject>
NSFetchRequest– <NSManagedObject>.predicate =
NSPredicate(format: String, args...)
NSManagedObjectContext– .fetch(request:
NSFetchRequest<NSManagedObject>) throws
Mobile Application Development in iOS 17
Core Data: Fetch
Mobile Application Development in iOS 18
func getPlayers() {let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Player")var players: [NSManagedObject]!do {
players = try self.managedObjectContext.fetch(fetchRequest)} catch {
print("getPlayers error: \(error)")}print("Found \(players.count) players")for player in players {
let name = player.value(forKey: "name") as! Stringlet health = player.value(forKey: "health") as! Intprint(" Found player \(name) with health \(health)")
}}
Core Data: Delete
Methods•
NSManagedObjectContext– .delete(object:
NSManagedObject)
NSManagedObjectContext– .save()
Mobile Application Development in iOS 19
Core Data: Delete
Mobile Application Development in iOS 20
func removePlayers() {let playerName = "Mario"let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Player")fetchRequest.predicate = NSPredicate(format: "name == %@", playerName)var players: [NSManagedObject]!do {
players = try self.managedObjectContext.fetch(fetchRequest)} catch {
print("removePlayers error: \(error)")}for player in players {
self.managedObjectContext.delete(player)}self.appDelegate.saveContext() // In AppDelegate.swift
}
SQLite
C API to SQL database•
Swi2 wrappers provided by SQLite.swi2•
github.com/stephencelis/SQLite.swi2–
Install via CocoaPods (see Miscellaneous Topics)–
Mobile Application Development in iOS 21
SQLite.swift: Create Database
• Connection(pathToDB: String) throws ->
Connection
• Table(name: String)
• Expression<Type>(name: String)
• Connection.run(Table.create() { t in
t.column(Expression<Type>)}) throws
Mobile Application Development in iOS 22
SQLite.swift: Create Database
Mobile Applica8on Development in iOS 23
import SQLiteclass ViewController: UIViewController {
var db: Connection!var playersTable: Table!var nameExp: Expression<String>!var healthExp: Expression<Int>!
func createDatabase() {// Connect to writable database in app’s Documents directory.let directoryURL = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask).first!let path = directoryURL.pathdb = try? Connection("\(path)/db.sqlite3")// Create Players tableplayersTable = Table("Players")nameExp = Expression<String>("name")healthExp = Expression<Int>("health")do {
try db?.run(playersTable.create(ifNotExists: true) { t int.column(nameExp)t.column(healthExp)})
} catch {print("error creating table")
}}
}
SQLite.swift: Insert
• Connection.run(Table.insert(Expression<Type>
<- Any?, …) throws
Mobile Application Development in iOS 24
SQLite.swift: Insert
Mobile Applica8on Development in iOS 25
func addPlayers() {do {
try db.run(playersTable.insert(nameExp <- "Mario", healthExp <- 100))try db.run(playersTable.insert(nameExp <- "Yoshi", healthExp <- 200))
} catch {print("insert error")
}}
SQLite.swift: Fetch
• Connection.scalar(Table.count) throws -> Int
• Connection.prepare(Table) throws
Mobile Application Development in iOS 26
SQLite.swift: Fetch
Mobile Applica7on Development in iOS 27
func getPlayers() {if let count = try? db.scalar(playersTable.count) {
print("Found \(count) players")if let players = try? db.prepare(playersTable) {
for player in players {print(" Found player \(player[nameExp]) with health \(player[healthExp])")
}}
}}
SQLite.swift: Delete
• Table.Filter(Expression<Type> == Any?)
• Connection.run(Filter.delete()) throws
Mobile Application Development in iOS 28
SQLite.swift: Delete
Mobile Applica6on Development in iOS 29
func removePlayers() {let marioFilter = playersTable.filter(nameExp == "Mario")do {
try db.run(marioFilter.delete())} catch {
print("delete error")}
}
Data Protection
Files encrypted and inaccessible with device •
locked
Can selec8vely encrypt files•
Mobile Application Development in iOS 31
Resources• File I/O
– developer.apple.com/documentation/foundation/filemanager
• Core Data– developer.apple.com/documentation/coredata
– www.raywenderlich.com/173972/getting-started-with-core-data-tutorial-2
• SQLite– github.com/stephencelis/SQLite.swift
• iCloud backup– developer.apple.com/icloud/documentation/data-storage
• Data Protection– developer.apple.com/documentation/uikit/core_app/protecting_the_user_s_privacy/encrypti
ng_your_app_s_files
Mobile Application Development in iOS 32