How to Save a Swift Array

how to save and read array of array in NSUserdefaults in swift?

The question reads "array of array" but I think most people probably come here just wanting to know how to save an array to UserDefaults. For those people I will add a few common examples.

String array

Save array

let array = ["horse", "cow", "camel", "sheep", "goat"]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedStringArray")

Retrieve array

let defaults = UserDefaults.standard
let myarray = defaults.stringArray(forKey: "SavedStringArray") ?? [String]()

Int array

Save array

let array = [15, 33, 36, 723, 77, 4]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedIntArray")

Retrieve array

let defaults = UserDefaults.standard
let array = defaults.array(forKey: "SavedIntArray") as? [Int] ?? [Int]()

Bool array

Save array

let array = [true, true, false, true, false]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedBoolArray")

Retrieve array

let defaults = UserDefaults.standard
let array = defaults.array(forKey: "SavedBoolArray") as? [Bool] ?? [Bool]()

Date array

Save array

let array = [Date(), Date(), Date(), Date()]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedDateArray")

Retrieve array

let defaults = UserDefaults.standard
let array = defaults.array(forKey: "SavedDateArray") as? [Date] ?? [Date]()

Object array

Custom objects (and consequently arrays of objects) take a little more work to save to UserDefaults. See the following links for how to do it.

  • Save custom objects into NSUserDefaults
  • Docs for saving color to UserDefaults
  • Attempt to set a non-property-list object as an NSUserDefaults

Notes

  • The nil coalescing operator (??) allows you to return the saved array or an empty array without crashing. It means that if the object returns nil, then the value following the ?? operator will be used instead.
  • As you can see, the basic setup was the same for Int, Bool, and Date. I also tested it with Double. As far as I know, anything that you can save in a property list will work like this.

Saving an array in Swift

You need to specify a file name

let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! 
let fileURL = dir.appendingPathComponent("file.txt")
// write to fileURL

Save array of Days in Swift 5

A better approach would be is to store the object of the class in userDefaults instead of storing particular properties of that class. And use [Date] instead of Date to save multiple days

For this first, you have Serialize the object to store in userDefaults and Deserialize to fetch the data from userDefaults.

import Foundation

class Day: Codable {

var date = Date()
var goalAmount: Drink
var consumedAmount: Drink

init(date: Date, goalAmount: Drink,consumedAmount: Drink ) {
self.date = date
self.goalAmount = goalAmount
self.consumedAmount = consumedAmount

}

static func saveDay(_ day : [Day]) {
do {
let object = try JSONEncoder().encode(day)
UserDefaults.standard.set(object, forKey: "days")
} catch {
print(error)
}

}

static func loadDay() {
let decoder = JSONDecoder()
if let object = UserDefaults.standard.value(forKey: "days") as? Data {
do {
let days = try decoder.decode([Day].self, from: object)

for day in days {
print("Date - ", day.date)
print("Goal Amount - ", day.goalAmount)
print("Consumed Amount - ",day.consumedAmount)
print("----------------------------------------------")
}

} catch {
print(error)
}

} else {
print("unable to fetch the data from day key in user defaults")
}
}
}

class Drink: Codable {
var typeOfDrink: String
var amountOfDrink: Float

init(typeOfDrink: String,amountOfDrink: Float ) {
self.typeOfDrink = typeOfDrink
self.amountOfDrink = amountOfDrink
}

}

Use saveAndGet() method to store and fetch details from userDefaults

func saveAndGet() {
// use any formats to format the dates
let date = Date()
let goalAmount = Drink(typeOfDrink: "Water", amountOfDrink: 5.0)
let consumedAmount = Drink(typeOfDrink: "Water", amountOfDrink: 3.0)

let day1 = Day(date: date, goalAmount: goalAmount, consumedAmount: consumedAmount)
let day2 = Day(date: date, goalAmount: goalAmount, consumedAmount: consumedAmount)
let day3 = Day(date: date, goalAmount: goalAmount, consumedAmount: consumedAmount)
let day4 = Day(date: date, goalAmount: goalAmount, consumedAmount: consumedAmount)

let days = [day1, day2, day3, day4]
Day.saveDay(days)

Day.loadDay()
}

How do I save a swift array?

Use NSUserDefaults.

Save array:

let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(myArray, forKey: "myarray")
defaults.synchronize()

Read array:

myArray = defaults.dataForKey("myarray") as Array

How to save a Float array in Swift as txt file

The answer to the question itself (save it as txt), you can save your array of floats as a JSON string. It should be pretty straight forward to encode and decode it using JSONEncoder/JSONDecoder.

let values: [Float] = [-.pi, .zero, .pi, 1.5, 2.5]

let encoded = try! JSONEncoder().encode(values)
print(String(data: encoded, encoding: .utf8)!) // "[-3.1415925025939941,0,3.1415925025939941,1.5,2.5]\n"
let decoded = try! JSONDecoder().decode([Float].self, from: encoded) // [-3.141593, 0, 3.141593, 1.5, 2.5]

"But it is not possible to initialize Data with Float values, or is it?"

Yes it if definitely possible to convert an Array of Float to Data/Bytes and read it back. It is also preferred to preserve the exact values avoiding the conversion to string:

extension Array {
var bytes: [UInt8] { withUnsafeBytes { .init($0) } }
var data: Data { withUnsafeBytes { .init($0) } }
}
extension ContiguousBytes {
func object<T>() -> T { withUnsafeBytes { $0.load(as: T.self) } }
func objects<T>() -> [T] { withUnsafeBytes { .init($0.bindMemory(to: T.self)) } }
}


let values: [Float] = [-.pi, .zero, .pi, 1.5, 2.5]
let bytes = values.bytes // [218, 15, 73, 192, 0, 0, 0, 0, 218, 15, 73, 64, 0, 0, 192, 63, 0, 0, 32, 64]
let data = values.data // 20 bytes
let minusPI: Float = data.subdata(in: 0..<4).object() // -3.141593
let loaded1: [Float] = bytes.objects() // [-3.141593, 0, 3.141593, 1.5, 2.5]
let loaded2: [Float] = data.objects() // [-3.141593, 0, 3.141593, 1.5, 2.5]

How to save a JSON array to Realm in Swift?

save(todoItem: listArray) doesn't work because save expects an [Object], but listArray is a [TodoListResponse].

What you are missing is the step that converts your codable struct TodoListResponse to the Realm model TodoIItemList. I would write the save method like this:

func save(_ todoListResponses: [TodoListResponse]) {
do{
try realm.write{
for response in todoListResponses {
let object = TodoIItemList()
object.title = response.title
object.completed = response.completed
realm.add(object)
}
}
}catch{
print(error)
}
}

Now save(todoItem: listArray) should work.

If there are many properties that needs to be set in TodoIItemList, you can move the "copying properties" logic to a convenience initialiser of TodoIItemList that initialises a TodoIItemList from a TodoListResponse.

how to save array to ios document directory?

We can't save struct object to NSArray directly and we even can't make use of any array of struct to save in Document Directory. So we need some conversions.

First of all decide the path to store in Document Directory. In this function we will pass the name of the array file to be stored in Document Directory

func getFilePath(fileName:String) -> String {
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let url = NSURL(fileURLWithPath: path)
let filePath = url.appendingPathComponent(fileName)?.path
return filePath!
}

Main Process starts from here. Now we will pass the Patient array of struct in this function which will convert in NSMutableArray and save in DocumentDirectory.

func convertAndSaveInDDPath (array:[Patient]) {
let objCArray = NSMutableArray()
for obj in array {

// we have to do something like this as we can't store struct objects directly in NSMutableArray
let dict = NSDictionary(objects: [obj.firstName ?? "",obj.lastName ?? ""], forKeys: ["firstName" as NSCopying,"lastName" as NSCopying])
objCArray.add(dict)
}

// this line will save the array in document directory path.
objCArray.write(toFile: getFilePath(fileName: "patientsArray"), atomically: true)
}

So, call this method for the saving process.

convertAndSaveInDDPath(array: offpatients)

In order to see the physical file, just print the result of getFilePath(fileName: "patientsArray"). It will print something like this according to your system settings.

/Users/rajan/Library/Developer/CoreSimulator/Devices/B8BD5017-4BD0-47F7-B840-BE9464817392/data/Containers/Data/Application/D09FFC21-D215-44C3-831B-95A470C41A47/Documents/patientsArray

Navigate to your generated path and you will find patientArray file saved in the Document Directory location.

Now in order to fetch it back in the same form (swift array of struct)

func getArray() -> [Patient]? {
var patientsArray = [Patient]()
if let _ = FileManager.default.contents(atPath: getFilePath(fileName: "patientsArray")) {
let array = NSArray(contentsOfFile: getFilePath(fileName: "patientsArray"))
for (_,patientObj) in array!.enumerated() {
let patientDict = patientObj as! NSDictionary
let patient = Patient(lastName: patientDict.value(forKey: "lastName") as? String, firstName: patientDict.value(forKey: "firstName") as? String)
patientsArray.append(patient)

}
return patientsArray
}
return nil
}

Just call this function and you will get your saved array back in the same swift array of struct form.

let patientRetrievedArray = getArray()

And you are done.

Hope this helps!



Related Topics



Leave a reply



Submit