Cant set Array in NSUserDefaults - ios

var arr = defaults.arrayForKey("kWeeks") as [WeekReport]?
if arr? {
var arr2 = arr!
arr2.append(report)
defaults.setObject(arr2, forKey: "kWeeks") // Crash
defaults.synchronize()
}
I try to set arr2 which will be the add after optional checking. But it crashes on setObject() with error: EXC_BAD_ACCESS
Ive checked, with println() and arr2 is not nil and contains the element which is appended in the sample above. And report is of type WeekReport.

var arr = defaults.arrayForKey("kWeeks") as [WeekReport]?
Is doing a forced casting to an optional array of WeekReport. Instead, you really want to do an optional casting:
if let arr = defaults.arrayForKey("kWeeks") as? [WeekReport] {
arr.append(report)
defaults.setObject(arr, forKey: "kWeeks")
defaults.synchronize()
}
This says, "if there is an array for "kWeeks" that can be cast to an array of WeekReport, do the following with it as arr"
You also need to make sure that WeekReport inherits from the NSCoding protocol so that it can be converted to data.

Related

Swift 3 User Defaults set dictionary crash

I have worked with Userdefaults many times before but in this case can't seem to figure out what would cause this crash to occur even though it is such a simple case.
Goal: UserDefaults.standard.set a dictionary with a value of an array of dictionary's
struct UDKey {
static let activityCount = "ActivityCount"
}
class MyClass {
let defaults = UserDefaults.standard
func initialize() {
let years = [ 2017: [[1:2],
[2:4],
[3:6],
[4:8],
[5:10],
[6:12],
[7:14],
[8:16],
[9:17],
[10:18],
[11:19],
[12:20]]]
if defaults.value(forKey: UDKey.activityCount) == nil {
defaults.set(years, forKey: UDKey.activityCount) // Crash - lldb
}
}
}
I have attempted setting others values with success, such as simple integers and strings. but this dictionary with a value of an array of dictionary's is having a problem.
What could be the cause for a UserDefaults Crash when setting a value.

iOS Swift 3 - Argument labels '(of:)' do not match any available overloads Error

I'm getting the error message Argument labels '(of:)' do not match any available overloads. Below is the code I'm using.
let prefs = UserDefaults.standard
var id: String!
if var array = prefs.string(forKey: "myArray"){
if let index = array.index(of: id) {
array.remove(at: index)
prefs.setValue(array, forKey: "myArray")
}
}
I've seen a lot of answers on Stack Overflow with very similar code to that. So I'm not quite sure why this wouldn't be working.
Basically I'm just trying to remove the element in the array that = id then set that new array to the user defaults.
Update
Just updated the code above to show how array is getting defined. id is a string that is defined in a separate section.
By accessing prefs.string(forKey: "myArray"), you are getting a String, not an array of strings. You should use this:
if var prefs.array(forKey: "myArray") as? [String] { }
or
if var prefs.value(forKey: "myArray") as? [String] { }
Make sure to not forget putting as! [String], because the first method returns [Any], an which can contain objects of any type, not specifically String. Then your error should be solved, because index(of: ) can only be used on Arrays of specified types.
Hope it helps!
Just make an alt + Click on an "array" variable to make sure it is of type Array ([String]), not a String. To apply .index(of:) method it must be an array.
Like this:
String does not have a method .index(of:). That's what the error is pointing at. And sure make a cast to [String]? if it fits.

iOS Swift Updating Dictionary In An Array

I have an array of dictionaries inside a dictionary. I initialize it like this:
var fillups:[NSMutableDictionary] = []
Then I load it like this:
fillups = userDefaults.object(forKey: car) as! NSArray as! [NSMutableDictionary]
Then when I try to update a dictionary element in the array I get the "mutating method sent to immutable object" error. Here's my code to update the record:
let dict=fillups[row]
dict.setValue(odometerField.text, forKey: "odometer")
dict.setValue(gallonsField.text, forKey: "gallons")
fillups[row]=dict
The error occurs in my first setValue line.
Objects that you retrieve from NSUserDefaults are immutable even if they were mutable when they were inserted. You need to take the immutable objects you get from defaults and create mutable versions of them. You also shouldn't force unwrap everywhere if you don't want your app to crash.
if let array = userDefaults.object(forKey: car) as? [NSDictionary] {
fillups = array.map { ($0.mutableCopy() as! NSMutableDictionary) }
}
You also don't need the fillips[row] = dict line since NSMutableDictionary is a reference type and editing the reference you pull out of the array is already editing the one inside the array.
If you want to mutate your dict, you need to declare it with 'var' not with 'let'; 'let' is for constants. Also fix the unwrapping problems pointed out by the comment
let dict=fillups[row]
should be
var dict=fillups[row]

Parse: Updating array

I'm trying to upload an array with the following code, but I am getting an error on the second to last line which says Cannot assign to value: function call returns immutable array
for object in objects! {
let newstring = NSString(format: ".0f", self.slider.value)
var newarray = [object.objectForKey("times")]
newarray.append(newstring)
object.objectForKey("times") = newarray
object.saveInBackground()
}
"times" is of type array in parse by the way.
Rather than requesting the array and trying to set it you should be using setObject:forKey: to replace the existing value.
object.setObject(newarray, forKey: "times")
May I suggest using the addObject:forKey: method instead?
for object in objects! {
let newstring = NSString(format: ".0f", self.slider.value)
object.addObject(newstring, forKey: "times")
object.saveInBackground()
}
It is much cleaner and doesn't require retrieval :)

iOS: how to convert NSUserDefaults stored AnyObject type to array

I have put an array into NSUserDefaults() like so:
NSUserDefaults.standardUserDefaults().setObject(users, forKey: "usersArray")
NSUserDefaults.standardUserDefaults().synchronize()
Then I pull it out like so:
fetchedUserArray = NSUserDefaults.standardUserDefaults().objectForKey("usersArray")
The problem I am facing is that once it is removed from NSUserDefaults it is of type NSArray, preventing me from manipulating it like a Swift array. I have tried this to convert the type, however the compiler does not recognize the variable "castedUsersArray" when it is used later in the code despite not raising any errors upon type casting:
var fetchedArray = NSUserDefaults.standardUserDefaults().objectForKey("usersArray") as? NSArray
var castedUsersArray = fetchedArray as AnyObject as [String]
I have spent a very long time on this with no success. The type constraints of Swift are driving me nuts.
Thank you,
Nick
You almost had it. Don't cast the objectForKey to an Array but rather an Array containing a certain type like you did with castedUsersArray. Don't throw away type information like you did with fetchedArray.
let users = ["Amy", "Bill", "Cindy"]
NSUserDefaults.standardUserDefaults().setObject(users, forKey: "usersArray")
NSUserDefaults.standardUserDefaults().synchronize()
let fetched = NSUserDefaults.standardUserDefaults().objectForKey("usersArray") as? [String] ?? []
The nil coalescing at the end of the line handles the empty NSUserDefaults case.
NSUserDefaults has a specific method to get your stored string arrays called stringArrayForKey:
let stringArray = ["Hello","playground"]
store your string array
NSUserDefaults.standardUserDefaults().setObject(stringArray, forKey: "stringArray")
load it when needed
if let loadedStringArray = NSUserDefaults.standardUserDefaults().stringArrayForKey("stringArray") {
print(loadedStringArray) // ["Hello", "playground"]
}

Resources