How to unarchive data in swift 3? - swift

I have an app where I save an array of CNContact to UserDefaults as such:
var contactsArray = [CNContact]()
let defaults = UserDefaults()
func (contact: CNContact){
contactsArray.append(contact)
let contactArrayArchive = NSKeyedArchiver.archivedData(withRootObject: contactArray) //archive the data
defaults.set(contactArrayArchive, forKey: "contactArray")
defaults.synchronize()
}
This archives the data to allow it to be saved to defaults. My issue is with how I can convert this data back to an array of CNContact in the viewDidLoad. I have seen many answers online which suggest to use NSKeyedArchiver.unarchiveObjectwithData but typing this into Xcode, with swift 3, says that the .unarchiveObjectwithData is not a member of NSKeyedArchiver. I keep looking for stuff about how to do this in swift 3 but have been unsuccessful. How can I unarchive the value?

You can use
NSKeyedUnarchiver.unarchiveObject(with: Data)
You have Used NSKeyedArchiver . You cannot use this to unarchive an Object.

If you press ⇧⌘0 to open the documentation and type nsk (3 characters are sufficient) you will see
To unarchive something you need the NSKeyedUnarchiver

Related

When do we need to use JSONEncoder and JSONDecoder with UserDefaults

To save some data to UserDefaults first we must encode it as JSON using JSONEncoder, which will send back a Data instance we can send straight to UserDefaults.Then reading saved data is a matter of converting from Data using a JSONDecoder. But sometimes we dont have to do that.
My question is will that method work anytime and when do i have to use it because i found this other solution without encode and decode:
var allWords = [String]()
var usedWords = [String]()
var currentWord: String?
In viewDidLoad:
let defaults = UserDefaults.standard
if let presentWord = defaults.object(forKey: "presentWord") as? String,
let savedWords = defaults.object(forKey: "savedWords") as? [String] {
title = presentWord
currentWord = presentWord
usedWords = savedWords
print("Loaded old game!")
Save method:
func save() {
let defaults = UserDefaults.standard
defaults.set(currentWord, forKey: "presentWord")
defaults.set(usedWords, forKey: "savedWords")
}
It's simple and faster way but Im not sure when i can use it with no worries
UserDefaults storage is a property list. NSString, NSData, NSArray, and NSDictionary are the only Cocoa classes that can be expressed directly in a property list. Moreover, an NSArray or NSDictionary can be expressed in a property list only if its elements are instances of those classes, along with NSDate and NSNumber. Those are the property list types.
If your Swift type bridges to a property list type, you can store it directly. So String will bridge to NSString, and an array of String will bridge to an NSArray of NSString, so you can store them directly.
But if what you've got is not a property list type, you need to transform it into a property list type before you can store it, and the usual solution is to transform it into an NSData (Swift Data). You don't have to use JSONEncoder for that but you do need to do it somehow.

Saving and retrieving a struct which is not codable to Userdefaults in Swift

I want to save a struct which can not be modified to UserDefaults in my code. I went through a number of solutions but everyone is advising to use Codable/NSCoding in the struct. I can not edit the struct. Does anyone have an idea how we can achieve this.
I tried to wrap the object to an NSDictionary but while trying to save, it crashes saying 'Attempt to insert non-property list object'. Is it because I have nil values in my model?
Any help is appreciated.
If you can't change your struct, then create an extension for it and conform it to Codable.
Once conformed to Codable, you can use JSONEncoder and JSONDecoder to convert to and from data and then save/retrieve from UserDefaults.
struct Sample {
var name = "Sample Struct"
}
extension Sample: Codable {
}
let obj = Sample()
let data = try? JSONEncoder().encode(obj)
//Saving in UserDefaults
UserDefaults.standard.set(data, forKey: "SampleStruct")
//Fetching from UserDefaults
if let data = UserDefaults.standard.data(forKey: "SampleStruct") {
let val = try? JSONDecoder().decode(Sample.self, from: data)
print(val) //Sample(name: "Sample Struct")
}
I tried to wrap the object to an NSDictionary
You can't save a custom model without conforming to Codable/NSCoding , if you don't need to conform then save it as a usual Array/Dictionary without wrapping any custom objects inside

Retrieving array of custom objects from UserDefaults using NSKeyedUnarchiever in swift

I have saved an array of custom objects that conforms to NSCoding protocol in UserDefaults using NSKeyedArchiver. But when I try to retrieve it using NSKeyedUnarchiver, i get runtime errors from Xcode. I have tried initialising NSArray using unarchived data but it also failed. My guess is that while unarchiving swift doesn't understand custom elements of this array. How shall I do it?
This is how I archived array of custom objects
static func saveCategoryList(_ categoryList : [Category]!) -> Void{
let userDefaults = UserDefaults.standard
let categoryListData = NSKeyedArchiver.archivedData(withRootObject: categoryList)
userDefaults.set(categoryListData, forKey: Constants.CategoryList)
userDefaults.synchronize()
}
I get error like the attached screenshot in runtime. I am quite sure I am not doing it right. How can get my desired result?

How to Store Data Sent back using the delegate method?

I have data sent back to my VC using the delegate method. How can I possibly store it so then I can use it to send to another VC?
func DataToPass(ArrayName: [String]) { //function from delegate
Datacollect = ArrayName
print(ArrayName)
}
Here's the function used in the delegate method that holds my data. ArrayName is an array containing my data.
Datacollect is an attempt to collect it, however nothing gets stored in Datacollect.
I have already assigned Datacollect as a String array.
var Datacollect = [String]()
How can I store the data to my VC from ArrayName?
There are lot of ways of storing data and one of the simplest ways to get started is to use the built-in UserDefaults.
This is how you might use the following code inside a method to store your DataCollect array.
Let defaults = UserDefaults.standard
defaults.set(DataCollect, forKey: "DataCollect")
To retrieve the data you could use the following code inside a method:
let defaults = UserDefaults.standard
let DataCollect = defaults.array(forkey: "DataCollect")

NSUser Defaults

I have tried an answer which doesn't work: Swift Saving user NSUser Defaults.
My problem is that i want to save : var myDict = [Int:String]() permanently using NSUser defaults.
My code is :
let userDefaults = NSUserDefaults.standardUserDefaults()
#IBAction func AddOneWord(sender: AnyObject) {
if newWord.text != "" {
myDict.updateValue(newWord.text!, forKey: 1)
self.Word1Dictionnary.text = myDict[1]
userDefaults.setValue(myDict, forKey: "1")
userDefaults.synchronize()
}
}
The problem is that I have this error when clicking on the button on my app (which is running) : Thread 1 : Signal SIGABRT.
NSUserDefaults can only store property-list objects. As noted in the Property List Programming Guide:
And although NSDictionary and CFDictionary objects allow their keys to be objects of any type, if the keys are not string objects, the collections are not property-list objects.
You cannot store an [Int: String] in NSUserDefaults. The key must be a string.