★ UserDefaultsのオブジェクトを取得する
let ud = UserDefaults.standard
★ NSUserDefaultsに初期値を登録する
var dictionary = ["key":"value"]
// 既に同じキーが存在する場合は初期値をセットせず、キーが存在しない場合だけ値をセットしてくれる
ud.registerDefaults(dictionary)
※ registerDefaults: メソッドを使って設定した初期値はアプリを終了すると消えてしまいますので使う時は注意!
★ キーを設定してオブジェクトを保存する
ud.setObject("string", forKey: "stringKey")
★ 保存する情報を即時に反映させる
ud.synchronize()
★ キーを設定してString型を取得する
var string = ud.stringForKey("stringKey")
var string:String = ud.stringForKey("stringKey")!
★ キーを設定してデータを削除する
ud.removeObjectForKey("stringKey")
★ Bool値を保存、取得する
var boolValue = true
ud.setBool(boolValue, forKey: "boolKey")
var boolValue = ud.boolForKey("boolKey")
★ Int型を保存、取得する
var intValue = 10
ud.setInteger(intValue, forKey: "intKey")
var intValue = ud.integerForKey("intKey")
★ float型を保存、取得する
var floatValue:Float = 123.4
ud.setFloat(floatValue, forKey: "floatKey")
var floatValue = ud.floatForKey("floatKey")
★ Double型を保存、取得する
var doubleValue: Double = 123.4
ud.setDouble(doubleValue, forKey: "doubleKey")
var doubleValue = ud.doubleForKey("doubleKey")
★ NSURL型を保存、取得する
var url:NSURL = NSURL(string: "https://www.apple.com")!
ud.setURL(url, forKey: "URLKey")
var urlValue = ud.URLForKey("URLKey")
★ 複雑な構造のデータ
typealias DataType = [[Int: [String]]]
// --- 保存 ---
let dataArray: DataType = [[1:["value1","value2"]],
[2:["value3","value4"]],
[3:["value5","value6"]],
[4:["value7","value8"]]]
let defaults = NSUserDefaults.standardUserDefaults()
var saveDataArray = [NSData]()
for data in dataArray {
let nsdata = NSKeyedArchiver.archivedDataWithRootObject(data)
saveDataArray.append(nsdata)
}
defaults.setObject(saveDataArray, forKey: "data")
defaults.synchronize()
// --- 読み込み ---
if let nsdataArray = defaults.objectForKey("data") as? [NSData] {
var dataArray: DataType = []
for data in nsdataArray {
if let data = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? [Int: [String]] {
dataArray.append(data)
}
}
print(dataArray[0][1]![1])
//=> value2
print(dataArray)
//=> [[1: ["value1", "value2"]], [2: ["value3", "value4"]], [3: ["value5", "value6"]], [4: ["value7", "value8"]]]
}
★ NSCodingとNSKeyedArchiverを使用したパターン
// DataModel
class Person: NSObject, NSCoding {
var name: String = ""
var age : Int = 0
init(name: String, age: Int) {
self.name = name
self.age = age
}
@objc required init(coder aDecoder: NSCoder) {
let name = aDecoder.decodeObjectForKey("name") as? String
let age = aDecoder.decodeObjectForKey("age") as? Int
if let name = name,age = age {
self.name = name
self.age = age
}
}
@objc func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(self.name, forKey: "name")
aCoder.encodeObject(self.age , forKey: "age")
}
}
extension NSUserDefaults {
var personArray: [Person] {
get{
let rowData: NSData = self.objectForKey("PersonData") as? NSData ?? NSData()
let datas = NSKeyedUnarchiver.unarchiveObjectWithData(rowData) as? [Person] ?? []
return datas
}
set(newDatas) {
let archive = NSKeyedArchiver.archivedDataWithRootObject(newDatas)
self.setObject(archive, forKey: "PersonData")
}
}
}
// Usage (以下の全てのパターンも使い方は同じ)
let data1 = Person(name: "MyName1", age: 20)
let data2 = Person(name: "MyName2", age: 21)
let data3 = Person(name: "MyName3", age: 22)
let defaults = NSUserDefaults.standardUserDefaults()
defaults.personArray = [data1, data2, data3]
defaults.synchronize()
let data = defaults.personArray
print(data[1].name, data[1].age)
//=> MyName2 21
★ Swift3
class Person: NSObject, NSCoding {
var name: String = ""
var age : Int64 = 0
init(name: String, age: Int) {
self.name = name
self.age = Int64(age)
}
required init?(coder aDecoder: NSCoder) {
let name = aDecoder.decodeObject(forKey: "name") as? String
let age = aDecoder.decodeInt64(forKey: "age")
if let name = name {
self.name = name
self.age = age
}
}
func encode(with aCoder: NSCoder) {
aCoder.encode(self.name, forKey: "name")
aCoder.encode(self.age , forKey: "age")
}
}
extension UserDefaults {
var personArray: [Person] {
get{
let rowData: NSData = self.object(forKey: "PersonData") as? NSData ?? NSData()
let datas = NSKeyedUnarchiver.unarchiveObject(with: rowData as Data) as? [Person] ?? []
return datas
}
set(newDatas) {
let archive = NSKeyedArchiver.archivedData(withRootObject: newDatas)
self.set(archive, forKey: "PersonData")
}
}
}
★ NSCodingとNSKeyedArchiverを使用しないパターン(Struct,ClassもOK)
// DataModel
struct Person {
let name: String
let age : Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
// StructをNSObjec型(NSDictionary)に変換することでUserDefaultsに保存する
extension NSUserDefaults {
var personArray: [Person] {
get {
let dictArray = self.objectForKey("PersonData") as? [NSDictionary] ?? []
let array = dictArray.reduce([]){ (ary, dict: NSDictionary) -> [Person] in
if let name = dict["name"] as? String, age = dict["age"] as? Int {
return ary + [Person(name: name, age: age)]
} else {
return ary
}
}
return array
}
set(personDatas) {
let newDatas: [NSDictionary] = personDatas.map {
["name": $0.name,
"age": $0.age] as NSDictionary
}
self.setObject(newDatas,forKey:"PersonData")
}
}
}
★ 相互変換するinitを定義する
// DataModel
struct Person {
let name: String
let age : Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
extension NSDictionary {
convenience init(_ person: Person) {
let dict = ["name": person.name, "age": person.age]
self.init(dictionary: dict)
}
}
extension Person {
init(_ dict: NSDictionary) {
let name = dict["name"] as? String ?? ""
let age = dict["age"] as? Int ?? 0
self.init(name: name, age: age)
}
}
extension NSUserDefaults {
var personArray: [Person] {
get {
let datas = self.objectForKey("PersonData") as? [NSDictionary] ?? []
return datas.map { Person($0) }
}
set(personDatas) {
let saveDatas = personDatas.map { NSDictionary($0) }
self.setObject(saveDatas,forKey: "PersonData")
}
}
}
★ クラスを拡張して保存できるようにする
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let defaults = NSUserDefaults.standardUserDefaults()
// 取得
let data = defaults.objectForKey("SaveKey")
print(data.dynamicType) // Optional<AnyObject>
var myClass: MyClass
if let data = data {
// UnArchive
myClass = NSKeyedUnarchiver.unarchiveObjectWithData(data as! NSData) as! MyClass
} else {
//保存データがない場合は新規にオブジェクト作成
myClass = MyClass()
myClass.intValue = 1
myClass.stringValue = "a"
}
print(myClass.intValue)
print(myClass.stringValue)
// 保存
let nsdata = NSKeyedArchiver.archivedDataWithRootObject(myClass)
defaults.setObject(nsdata, forKey:"SaveKey")
defaults.synchronize()
}
}
// NSUserDefaultに保存できるクラス
class MyClass: NSObject, NSCoding {
var intValue: Int = 0
var stringValue: String = ""
override init() {
super.init()
}
// Encode
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(intValue, forKey: "IntValueKey")
aCoder.encodeObject(stringValue, forKey: "StringValueKey")
}
// Decode
required init(coder: NSCoder) {
self.intValue = coder.decodeObjectForKey("IntValueKey") as! Int
self.stringValue = coder.decodeObjectForKey("StringValueKey") as! String
}
}
★ UIImageの配列をNSUserDefaultsに保存する
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var imageV1: UIImageView!
@IBOutlet weak var imageV2: UIImageView!
@IBOutlet weak var imageV3: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
let photos = [UIImage(named: "image1")!, UIImage(named: "image2")!, UIImage(named: "image3")!]
// [UIImage] → [NSData]
let dataImages: [NSData] = photos.map { (image) -> NSData in
UIImagePNGRepresentation(image)!
}
defaults.setObject(dataImages, forKey: "photos")
defaults.synchronize()
let images = defaults.objectForKey("photos") as! [NSData]
imageV1.image = UIImage(data: images[0])
imageV2.image = UIImage(data: images[1])
imageV3.image = UIImage(data: images[2])
}
}
★ enum(関連型)をUserDefaultsに保存する
参考プロジェクト: ReviewAlert
enum ReviewStatus {
// Reviewの状態
case none(count: Int)
case after(count: Int)
case never
// Review Statusを保存
func saveReviewStatus() {
var value: [String: AnyObject]!
switch self {
case .none(let count) : value = ["none" : count]
case .after(let count): value = ["after": count]
case .never : value = ["never": ""]
}
NSUserDefaults.standardUserDefaults().setObject(value, forKey: "ReviewStatusKey")
NSUserDefaults.standardUserDefaults().synchronize()
}
// Review Statusを呼び出し
static func readReviewStatus() -> ReviewStatus {
if let status = NSUserDefaults.standardUserDefaults().objectForKey("ReviewStatusKey") as? [String: AnyObject] {
let key = status.keys.first!
let value = status[key]
switch key {
case "none" : return .none(count: value as! Int)
case "after": return .after(count: value as! Int)
default : return .never
}
} else {
// 初期値
return .none(count: 0)
}
}
}
★ NSUserDefaults の内容を全削除する
let appDomain = NSBundle.mainBundle().bundleIdentifier!
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(appDomain)
★ Class配列を保存する(Swift4.1)
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let item1 = Item(time: "01.55", date: "2018/05/05", compareTime: 01.55)
let item2 = Item(time: "01.23", date: "2018/05/04", compareTime: 1.23)
let item3 = Item(time: "00.23", date: "2018/05/06", compareTime: 0.23)
let saveItems = [item1, item2, item3]
// 保存
let userDefaults = UserDefaults.standard
let archivedObject = NSKeyedArchiver.archivedData(withRootObject: saveItems)
userDefaults.set(archivedObject, forKey: "ItemSaveKey")
userDefaults.synchronize()
// 取得
var resultItems: [Item] = []
if let itemData = userDefaults.object(forKey: "ItemSaveKey") as? Data,
let getItems = NSKeyedUnarchiver.unarchiveObject(with: itemData) as? [Item] {
// ソート
resultItems = getItems.sorted{ $0.time < $1.time }
}
// resultItems => [Item(time: "00.23", date: "2018/05/06", compareTime: 0.23),
// Item(time: "01.23", date: "2018/05/04", compareTime: 1.23),
// Item(time: "01.55", date: "2018/05/05", compareTime: 01.55)]
}
}
class Item: NSObject, NSCoding {
enum ItemKey: String {
case itemTimeKey
case itemDateKey
case itemCompareTimeKey
}
/// タイム表示用
var time: String
/// 日付
var date: String
/// タイム比較用
var compareTime: Double
init(time: String, date: String, compareTime: Double) {
self.time = time
self.date = date
self.compareTime = compareTime
}
required init?(coder aDecoder: NSCoder) {
guard let time = aDecoder.decodeObject(forKey: Item.ItemKey.itemTimeKey.rawValue) as? String,
let date = aDecoder.decodeObject(forKey: Item.ItemKey.itemDateKey.rawValue) as? String else {
return nil
}
self.time = time
self.date = date
self.compareTime = aDecoder.decodeDouble(forKey: Item.ItemKey.itemCompareTimeKey.rawValue)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(time, forKey: Item.ItemKey.itemTimeKey.rawValue)
aCoder.encode(date, forKey: Item.ItemKey.itemDateKey.rawValue)
aCoder.encode(compareTime, forKey: Item.ItemKey.itemCompareTimeKey.rawValue)
}
}
- Swift4
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var result: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// 保存
let controller = UserDefalutsController(sourceName: "Name", value: 1.0)
UserDefaults.standard.userDefalutsController = controller
// 読み込み
if let controller = UserDefaults.standard.userDefalutsController {
controller.setAddNum(1.0)
print(controller.getNum())
//=> 2.0
}
}
}
class UserDefalutsController: NSObject, NSCoding {
let sourceName: String
var value: Double
init(sourceName: String, value: Double) {
self.sourceName = sourceName
self.value = value
}
required init?(coder aDecoder: NSCoder) {
self.sourceName = aDecoder.decodeObject(forKey: "sourceName") as? String ?? ""
self.value = aDecoder.decodeDouble(forKey: "value")
}
func encode(with aCoder: NSCoder) {
aCoder.encode(sourceName, forKey: "sourceName")
aCoder.encode(value, forKey: "value")
}
func setAddNum(_ numner:Double){
value += numner
}
func getNum() -> Double{
return value
}
}
extension UserDefaults {
var userDefalutsController: UserDefalutsController? {
get{
guard let data = self.object(forKey: "volume") as? NSData,
let controller = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? UserDefalutsController else { return nil }
return controller
}
set(controller) {
guard let controller = controller else { return }
let archive = NSKeyedArchiver.archivedData(withRootObject: controller)
self.set(archive, forKey: "volume")
}
}
}