Swift 4 - Xcode 9 store Array in UserDefaults via Json - arrays

Goal: is to save array data to be retrieved by next session
Approach: encode the array to Json, store in UserDefaults, then retrieve data and decode to the array.
Maybe a better way, assume wrapping in Json is the best way to transport to UserDefaults
I think my encode and save to UserDefault works & I can return the object and print a size... don't know how to decode back to my array?
var matrixArray = [matrixItem]()
var returnArray: Decodable = [returnMatrixItem]()
let encoder = JSONEncoder()
let decoder = JSONDecoder()
#IBAction func restoreFrom(_ sender: Any) {
let restoredJson: Data = UserDefaults.standard.data(forKey: "storeArray")!
// its here that i can't determine how to decode the return value to my array
// error: cannot invoke decode with an argument list of type([Decodeable], from Data:)
try! JSONDecoder().decode([returnArray.self], from: restoredJson)
print("return json size \(restoredJson)")*
}
#IBAction func appendItem(_ sender: Any) {
if let newValue = newItem.text {
print(newValue)
newItem.text = " "
let itemToAdd = matrixItem(matrixName: newValue, matrixDescription: itemDescription.text!)
matrixArray.append(itemToAdd)
print(matrixArray)
let jsonData = try! encoder.encode(matrixArray)
print("Print json data \(jsonData)")
UserDefaults.standard.set(jsonData, forKey: "storeArray")
}
}

Related

How to set custom class array data in UserDefalts in swift 4

I have A Array List
private var deviceArray: [SearchPeripheral]? = []
I want to hold data of device array in UserDefaults but its crashing when I store it.
please help me on it
Thank you.
You can't store custom models in UserDefaults. You can make the following improvements to save your objects as [[String:Any]]
struct SearchPeripheral: Codable {
let name: String
let model: String
}
extension SearchPeripheral {
var dictionary: [String:Any] {
let data = try! JSONEncoder().encode(self)
let any = try! JSONSerialization.jsonObject(with: data)
return any as! [String:Any]
}
init?(_ dict: [String:Any]) {
guard let peripheral = (try? JSONSerialization.data(withJSONObject: dict)).flatMap({
try? JSONDecoder().decode(SearchPeripheral.self, from: $0)
}) else {
return nil
}
self = peripheral
}
}
Saving Array of SearchPeripheral:
func save(_ peripherals: [SearchPeripheral]) {
let allPeripherals = peripherals.compactMap({$0.dictionary})
UserDefaults.standard.set(allPeripherals, forKey: "peripherals")
}
Getting Array of SearchPeripherals:
func getPeripherals() -> [SearchPeripheral] {
let allPeripherals = UserDefaults.standard.array(forKey: "peripherals") as? [[String:Any]] ?? []
let peripherals = allPeripherals.compactMap(SearchPeripheral.init)
return peripherals
}

How to take a function result and turn it into a key value pair array

I am fairly new to Swift but I have a function that returns a key value pair result of numbers
func dataPostRequest(_ url:String,_ paramString:String)
{
let url:NSURL = NSURL(string: url)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url as URL)
request.httpMethod = "POST"
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest) {
(
data, response, error) in
guard let _:NSData = data as NSData?, let _:URLResponse = response, error == nil else {
print("error")
return
}
if let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
{
print(dataString)
}
}
task.resume()
}
I am able to call the function like this:
dataPostRequest("https://myserver.com/","user_email=emailtest.com")
This works correctly but I want to now use the data that I've pulled and display it in a Table View. I have my tableView set up correctly but I am wondering how I can take my function and turn it into a key value pair array or a dictionary that I can use. I have tried creating an empty dictionary and set my function call to it but I get an error:
var emptyDictionary = [Int: Int]()
emptyDictionary = dataPostRequest("https://myserver.com/","user_email=emailtest.com")
And no matter what variation I try I keep getting:
Cannot assign value of type '()' to type '[Int : Int]'
Any guidance would be greatly appreciated.
dataPostRequest has no return value (aka ()). You can decode the received data in the completion handler and assign it to the dictionary. See the comment line below.
If you need to proceed in another function you have to add a completion handler described here.
Basically don't use NS... classes in Swift at all if there are native counterparts. And don't annotate types the compiler can infer.
The native Swift version is
func dataPostRequest(with url:String, paramString : String)
{
let url = URL(string: url)!
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = paramString.data(using: .utf8)
let task = session.dataTask(with: request) { data, response, error in
if let error = error {
print(error)
return
}
let dataString = String(data: data!, encoding: .utf8)!
print(dataString)
// here decode the data to the desired type and assign it to emptyDictionary
}
task.resume()
}

Save and Append an Array in UserDefaults from ImagePickerControllerImageURL in Swift

I'm having an issue saving and retrieving an array in UserDefaults from UIImagePickerControllerImageURL. I can get the array after synchronizing, but I am unable to retrieve it. myArray is empty.
The testImage.image does get the image, no problems there.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let imageURL: URL = info[UIImagePickerControllerImageURL] as! URL
//test that imagepicker is actually getting the image
let imageData: NSData = try! NSData(contentsOf: imageURL)
let cvImage = UIImage(data:imageData as Data)
testImage.image = cvImage
//Save array to UserDefaults and add picked image url to the array
let usD = UserDefaults.standard
var array: NSMutableArray = []
usD.set(array, forKey: "WeatherArray")
array.add(imageURL)
usD.synchronize()
print ("array is \(array)")
let myArray = usD.stringArray(forKey:"WeatherArray") ?? [String]()
print ("myArray is \(myArray)")
picker.dismiss(animated: true, completion: nil)
}
There are many issue here.
Do not use NSData, use Data.
Do not use NSMutableArray, use a Swift array.
You can get the UIImage directly from the info dictionary`.
You can't store URLs in UserDefaults.
You save array to UserDefaults before you update the array with the new URL.
You create a new array instead of getting the current array from UserDefaults.
You needlessly call synchronize.
You needlessly specify the type for most of your variables.
Here is your code updated to fix all of these issues:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
testImage.image = image
}
if let imageURL = info[UIImagePickerControllerImageURL] as? URL {
//Save array to UserDefaults and add picked image url to the array
let usD = UserDefaults.standard
var urls = usD.stringArray(forKey: "WeatherArray") ?? []
urls.append(imageURL.absoluteString)
usD.set(urls, forKey: "WeatherArray")
}
picker.dismiss(animated: true, completion: nil)
}
Note that this saves an array of strings representing each URL. Later on, when you access these strings, if you want a URL, you need to use URL(string: arrayElement).

How we can find an element from [AnyObject] type array in swift

I have [AnyObject] array
var updatedPos = [AnyObject]()
I am setting data in that according to my requirement like!
let para:NSMutableDictionary = NSMutableDictionary()
para.setValue(posId, forKey: "id")
para.setValue(posName, forKey: "job")
let jsonData = try! NSJSONSerialization.dataWithJSONObject(para, options: NSJSONWritingOptions())
let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding) as! String
self.updatedPos.append(jsonString)
Now in my code i have some requirement to remove the object from this array where id getting matched according to requirement Here is the code which i am trying to implement
for var i = 0; i < updatedPos.count; i++
{
let posItem = updatedPos[i]
print("Id=\(posItem)")
let pId = posItem["id"] as? String
print("secRId=\(pId)")
if removeId! == pId!
{
updatedPos.removeAtIndex(i)
}
}
Here print("Id=\(posItem)") give me output asId={"id":"51","job":"Programmer"} but here i am not able to access id from this object. here print("secRId=\(pId)") give me nil
First of all use native Swift collection types.
Second of all use types as specific as possible.
For example your [AnyObject] array can be also declared as an array of dictionaries [[String:AnyObject]]
var updatedPos = [[String:AnyObject]]()
Now create the dictionaries and add them to the array (in your example the dictionary is actually [String:String] but I keep the AnyObject values).
let para1 : [String:AnyObject] = ["id" : "51", "job" : "Programmer"]
let para2 : [String:AnyObject] = ["id" : "12", "job" : "Designer"]
updatedPos.append(para1)
updatedPos.append(para2)
If you want to remove an item by id use the filter function
let removeId = "12"
updatedPos = updatedPos.filter { $0["id"] as? String != removeId }
or alternatively
if let indexToDelete = updatedPos.indexOf{ $0["id"] as? String == removeId} {
updatedPos.removeAtIndex(indexToDelete)
}
The JSON serialization is not needed for the code you provided.
PS: Never write valueForKey: and setValue:forKey: unless you know exactly what it's doing.
After some little bit stuffs I have found the very easy and best solution for my question. And I want to do special thanks to #vadian. Because he teach me new thing here. Hey Thank you very much #vadian
Finally the answer is I had covert posItem in json Format for finding the id from Id={"id":"51","job":"Programmer"} this string
And the way is
let data = posItem.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
if let dict = json as? [String: AnyObject] {
let id = dict["id"]
if removeId! == id! as! String
{
updatedLoc.removeAtIndex(i)
}
}
}
catch {
print(error)
}

Parsing JSON into swift predefined array

I am trying to get items from an api (JSON) and to parse it into a predefined swift array. I have searched and looked for hours but due to my lack of skills I wasn't able to find anything suitable my case.
My predefined array looks like this:
init?(participants: String, photoguest: UIImage?, photohome: UIImage?, time: String, stadium: String, channel: String)
the JSON structure is like this(entire json file):
{"gameId":"255","gameWeek":"17","gameDate":"2016-01-03","awayTeam":"SEA","homeTeam":"ARI","gameTimeET":"4:25 PM","tvStation":"FOX","winner":"SEA"}
My current code looks like this (Games is the class where I connect variables from array with table cell items):
var gameplan = [Games]()
func loadNFLgames(){
let apiURL = NSURL(string: "http://www.fantasyfootballnerd.com/service/schedule/json/test/")
let data: AnyObject? = NSData(contentsOfURL: apiURL!)
let homeTeam = (data as! NSDictionary)["homeTeam"] as! String
let awayTeam = (data as! NSDictionary)["awayTeam"] as! String
let gameDate = (data as! NSDictionary)["gameDate"] as! String
let gameTimeET = (data as! NSDictionary)["gameTimeET"] as! String
let tvStation = (data as! NSDictionary)["tvStation"] as! String
/*
for schleife mit API daten:
for gameWeek = currentWeek{ //every game where gameWeek matches currentWeek
*/
// create variables from api calls
let api_guest = awayTeam
let api_home = homeTeam
let api_tvhost = tvStation
let api_time = gameDate + ", " + gameTimeET + " ET" // convert gameDate to day e.g. SUN
let api_stadion = "N/A"
// prepare data for array
let gamedata = Games(participants: api_guest+" # "+api_home, photoguest: UIImage(named: api_guest), photohome: UIImage(named: api_home), time: api_time, stadium: api_stadion, channel: api_tvhost)!
// add data to array
gameplan.append(gamedata)
}
I am getting the following error:
Could not cast value of type '_NSInlineData' (0x1a0cfd428) to
'NSDictionary' (0x1a0cf3380).
EDIT: The error is being thrown here:
let homeTeam = (data as! NSDictionary)["homeTeam"] as! String
Your help is highly appreciated.
Thanks in advance!
hello your data variable doesn't contain the Json you r looking for. so you have to serialize it to json like alexander suggested but NSJSONSerialization can throw an error so we have tu put in in try
so your code will be something like this (i suggest always using dispatch_async to make it in background thread than use the completion closure to get your result)-->
func loadNFLgames(completionClosure: (result : [Games]) ->()){
let queue: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(queue, {
let URL = "http://www.fantasyfootballnerd.com/service/schedule/json/test/"
print(URL)
if let data = NSData(contentsOfURL: NSURL(string: URL)!){
if let JsonObject = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSMutableDictionary{
print(JsonObject)
//here you can loop through the JsonObject to get the data you are looking for
//when you get your array of Games just pass it the the completion closure like this
completionClosure(result: gameplan)
}
}
})
}
PS: please let me know if you need more help.
Your data variable is NSData type (not NSDictionary). You have to convert it in order to use it. Try something like that:
let decodedJson = NSJSONSerialization.JSONObjectWithData(data, options: nil) as! NSDictionary
And than you can use it like standard dictionary
let homeTeam = decodedJson["homeTeam"] as! String

Resources