Saving an array of objects in UserDefaults - swift

Using swift 3.0, I'm trying to add an array of objects into user defaults. As this isn't one of the regular UserDefault types I've realised that the object or array of objects (can't work out which one) will need to be parsed to the type NSData to then be added to UserDefaults.
My attempt so far is the following:
Within the object
func updateDefaults()
{
let data = NSData(data: MyVariables.arrayList)
UserDefaults.standard.set(data, forKey: "ArrayList")
}
Where MyVariables.arrayList is the array of objects.
Lastly, if possible it would be nice to know how to retrieve this from UserDefaults and convert it to the original one-dimensional array of objects.
Thanks
REPOSITORY: https://github.com/Clisbo/ModularProject

You can't save your custom array in NSUserDefaults. To do that you should change them to NSData then save it in NSUserDefaults Here is the code.
var custemArray: [yourArrayType] {
get {
if let data = NSUserDefaults.standardUserDefaults().objectForKey("yourKey") as? NSData {
let myItem = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? yourType
}
}
set {
let data =NSKeyedArchiver.archivedDataWithRootObject(yourObject);
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "yourKey")
NSUserDefaults.standardUserDefaults().synchronize()
}
}

Related

Unarchiving NSMutableArray in Swift 4

I'm adding objects to an NSMutableArray and archiving it with NSKeyedArchiver and UserDefaults.
Objects are added to the array, which I can see from the log console. I can also see that the archived objects contains the object.
The problem is that I whenever I unarchive the objects and add them to the mutable array, it always returns 1, no matter how many object I add.
Here's what I got:
Save objects to the array
trackNumberOfQuestionPlayed.add(questionsArray[randomQuestion] as AnyObject)
let saveQuestionsPlayed = NSKeyedArchiver.archivedData(withRootObject: trackNumberOfQuestionPlayed)
UserDefaults.standard.set(saveQuestionsPlayed, forKey: "QuestionsPlayed")
UserDefaults.standard.synchronize()
print(UserDefaults.standard.object(forKey: "QuestionsPlayed"))
Retrieve the objects
if let data = UserDefaults.standard.object(forKey: "QuestionsPlayed") as? Data {
if let trackNumberOfQuestionPlayed = (NSKeyedUnarchiver.unarchiveObject(with: data) as? NSMutableArray)
{
// In here you can access your array
print("Number of questions array is NOT empty: \(trackNumberOfQuestionPlayed.count)")
}
}
OK, I'm answering my own question. It turns out with a little bit tweaking you can save an array as described in my question. It turned out that some other code in my quiz game made a mess of it all. Sorted it out, and now the code below works:
Save objects to the array
trackNumberOfQuestionPlayed.add(questionsArray[randomQuestion] as AnyObject)
let saveQuestionsPlayed = NSKeyedArchiver.archivedData(withRootObject: trackNumberOfQuestionPlayed)
UserDefaults.standard.set(saveQuestionsPlayed, forKey: "QuestionsPlayed")
UserDefaults.standard.synchronize()
print("Count: \(trackNumberOfQuestionPlayed.count)")
Retrieve the objects
if let data = UserDefaults.standard.object(forKey: "QuestionsPlayed") as? Data {
if let trackNumberOfQuestionPlayed = (NSKeyedUnarchiver.unarchiveObject(with: data) as? NSMutableArray)
{
// In here you can access your array
self.trackNumberOfQuestionPlayed = trackNumberOfQuestionPlayed
print("Number of questions array is NOT empty: \(trackNumberOfQuestionPlayed.count)")
}
} else {
trackNumberOfQuestionPlayed = NSMutableArray()
print("questionsplayed is empty")
}

Swift JSON to Dictionary<String: Any>. Then cast "Any" as NSMutableArray

I am trying to read from a JSON String and draw a graph with its data:
{"y-axis-data":{"min":0.0,"max":1000,"Step":100.0},"x-labels":[1994,2000,2005],"y-values":[20,305,143]}
I wrote a function to create a dictionary from the string:
func jsonToDictionary(jsonString: String) -> [String: Any]? {
if let jsonData: Data = jsonString.data(using: String.Encoding.utf8) {
do {
return try (JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any])!
} catch {
some bla bla
}
}
return nil
}
The return dictionary should count 3 elements inside when I pass my JSON string, and it does.
I can then change of some variables (Double) which are 0 until now and give them the values of min max and Step from the "y-axis-data" key of my dictionary, using {"min":0.0,"max":1000,"Step":100.0} as a dictionary it self. Works fine.
My trouble comes when trying to initialize other atributes:
self.my_view!.x-labels = (jsonToDictionary!["x-labels"]) as? NSMutableArray
my_view has already been initialized as UIViewCustomClass(frame: someFrame)
myview.x-labels is an NSMutableArray and it is initialized as nil. After executing that line of code it is still nill, of course myview.x-labels.count is nil. if I do it this way:
self.my_view!.x-labels = (jsonToDictionary!["x-labels"]) as! NSMutableArray
I get a warning :
Treating a forced downcast to NSMutableArray as optional will never produce nil.
It then crashes on runtime with this error:
Could not cast value of type '__NSArrayI' (0x110ed5448) to 'NSMutableArray' (0x110ed4598).
of course the exact same thing happens with "y-values"
What is the right way to do this?
It was because your json!["x-labels"] is implicitly treated as NSArray, so you somehow had to do a "double-force-cast"
// get the converted json
let j = jsonToDictionary(jsonString: dict)
// double cast
let m = (j!["x-labels"] as! NSArray).mutableCopy() as! NSMutableArray
Result:
I think, JSONSerialization class converts into Array, and then Swift cannot cast Array to NSMutableArray. You can do this (Swift4):
let array = (jsonToDictionary!["x-labels"]) as? [Int]
if array != nil {
self.my_view!.x-labels = NSMutableArray(array: array!)
}

How to get some data out of an array in swift?

Here is my problem: I have an plist file, which have a simple strut:
root object is an array, and there are 2 sections in the array, each of them are dictionary including 2 pair key-value data:
and I'm going to create a tableView to show the datas, but I can't get the content out of the array :
here is how i declared my dataArray:
var plistArray = [AnyObject]()
can some one help me?
You need to properly cast at each level:
if let innerArray = plistArray[0] as? [AnyObject] {
if let dataDic = innerArray[indexPath.row] as? [String:String] {
if let imageName = dataDic["Pic"] {
cell?.imageView?.image = UIImage(named: imageName)
}
}
}
But why are you using AnyObject when you know what the plist contains? Use proper types. You know it's an array of arrays of dictionaries with String keys and String values.
var plistArray = [[[String:String]]]()
Then all you need is:
if let imageName = plistArray[0][indexPath.row]["Pic"] {
cell?.imageView?.image = UIImage(named: imageName)
}

Swift core data FetchRequest NSData to UIIMage

Good morning all, I am using Swift "new for me" and core data I am trying to fetch my stored UIIMage from core data the following way. FYI it is saved as Binary Data in core. And I can see the data if I NSLog it. My Fetch Request looks like this. I have NO ERRORS but my image is not showing.
When I save to Core Data the NSLog looks like this..
Did I get to Save Image
2015-10-12 09:05:43.307 Car-Doc-Safe-Plus[13972:3524049] The NewImage has this in it (entity: Documents; id: 0x7fd4c0432060 ; data: {
autoClub = nil;
driverLicense = <89504e47 0d0a1a0a 0000000d 49484452 00000215 00000155 08020000 00d7368a d8000000 01735247 4200aece 1ce90000 001c>;
insuranceID = nil;
noteText = nil;
plate = nil;
registration = nil;
})
But when i Fetch it looks like this..
The Request has this in it (entity: Documents; predicate: ((null)); sortDescriptors: ((null)); type: NSManagedObjectResultType; )
**override func viewDidLoad() {
super.viewDidLoad()
let appDel:AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
let context:NSManagedObjectContext = appDel.managedObjectContext!
let request = NSFetchRequest(entityName: "Documents")
request.returnsObjectsAsFaults = false;
let results : NSArray
try! results = context.executeFetchRequest(request)
if results.count > 0 {
let res = results[0] as! NSManagedObject
carImageView.image = res.valueForKey("driverLicense")as? UIImage
}
}**
I know I am missing something but I cannot figure it out. Any help is greatly appreciated.
JZ
The "binary data" type in Core Data is intended for reading and writing NSData objects. Since you want to read/write UIImage, you need to use the "transformable" type. With transformable, Core Data will attempt to use NSCoding to encode/decode the data, converting it to/from NSData as needed (Swift as? will not do this). Since UIImage conforms to NSCoding, you don't need to do any extra work except to tell Core Data to convert the data.

UIColor in NSUserDefaults Swift / iOS 8

I'm writing a Swift app for iOS. I need to set and later retrieve a UIColor object to NSUserDefaults.
I set it like this:
var userSelectedColor : NSData? = (NSUserDefaults.standardUserDefaults().objectForKey("UserSelectedColor") as? NSData)
if (userSelectedColor == nil) {
var colorToSetAsDefault : UIColor = UIColor.redColor()
var data : NSData = NSKeyedArchiver.archivedDataWithRootObject(colorToSetAsDefault)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "UserSelectedColor")
NSUserDefaults.standardUserDefaults().synchronize()
println("SET DEFAULT USER COLOR TO RED")
}
But I can't seem to get it back because the unarchive method on NSKeyedArchiver seems to be missing in Swift.
var userSelectedColorData: NSData? = (NSUserDefaults.standardUserDefaults().objectForKey("UserSelectedColor") as NSData)
var userSelectedColor : UIColor? = NSKeyedArchiver.unarchiveObjectWithData(userSelectedColorData)
What is the proper way to do this in Swift / iOS 8?
Unarchiving is done with NSKeyedUnarchiver, not with NSKeyedArchiver. You also should
use conditional casts (as?) to ensure that the application does not crash if the
saved user default is not of the expected type:
if let userSelectedColorData = NSUserDefaults.standardUserDefaults().objectForKey("UserSelectedColor") as? NSData {
if let userSelectedColor = NSKeyedUnarchiver.unarchiveObjectWithData(userSelectedColorData) as? UIColor {
println(userSelectedColor)
}
}