Casting struct to NSUserDefaults in Swift? - ios

Is there a way I can cast this Swift data set in someway to a form that is acceptable to NSUserDefauts? i.e. NSObject NSSet? (p.s. I realize NSUserDefaults isn't for this type of data, but I'm just testing)
struct Users {
var name: String = ""
var stores: [Store]
}
struct Store {
var name: String = ""
var clothingSizes = [String : String]()
}
init() {
let userDefaults = NSUserDefaults.standardUserDefaults()
if let usersPeople = userDefaults.valueForKey("Users") as?

I think you can use Dictionary. You'll need to make method to wrap data to struct and vice versa.
For example:
var users : [String: AnyObject]()
users["name"] = "SomeName"
users["stores"] = yourStoreArray
NSUserDefaults.standardUserDefaults().setObject(users, forKey: "Users")
something like that.
And when you need to get struct
if let myDictionaryFromUD = userDefaults.objectForKey("Users") as? [String:AnyObject]{
self.users = Users(myDictionaryFromUD["name"], stores: myDictionaryFromUD["stores"] as! [Store])
}
I aslo assume that you will save to userDefaults array of Users. In this case, you will save [[String: AnyObject]] but mechanics the same.

I don't know that this is the best way to do this but you can try this.
struct Users {
var name: String = ""
var stores: [Store]
}
struct Store {
var name: String = ""
var clothingSizes = [String : String]()
}
var Advert = [Users]()
init() {
NSUserDefaults.standardUserDefaults().setObject(Advert[0].name, forKey: "NameYouWant")
}

Related

The array of String property in a managed object constantly nil

First, I'm extracting the content from the text fields into a dictionary:
var dict: [String: String] = [:]
for metricPair in metricStackView.arrangedSubviews {
if metricPair.subviews[0] is UITextField {
let unitTextField = metricPair.subviews[0] as! UITextField
let valueTextField = metricPair.subviews[1] as! UITextField
if let textContent = unitTextField.text, let valueTextContent = valueTextField.text {
let trimmedKey = textContent.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedValue = valueTextContent.trimmingCharacters(in: .whitespacesAndNewlines)
dict.updateValue(trimmedValue, forKey: trimmedKey)
}
}
}
And I'm saving it to Core Data:
let goal = Goal(context: self.context)
goal.date = Date()
for item in dict {
goal.metrics?.append(item.key)
}
goal.progress.insert(progress)
My managed object looks like this:
extension Goal {
#nonobjc public class func createFetchRequest() -> NSFetchRequest<Goal> {
return NSFetchRequest<Goal>(entityName: "Goal")
}
#NSManaged public var date: Date
#NSManaged public var metrics: [String]?
#NSManaged public var progress: Set<Progress>
}
I keep getting nil for the metrics property of [String] type even before the context is saved. When I log item.key in:
for item in dict {
goal.metrics?.append(item.key)
}
the content is showing up properly.
As far as I can tell from the above code, metrics array is not initialized.
Try replacing this line:
goal.metrics?.append(item.key)
With these lines:
if case nil = goal.metrics?.append(item.key) {
goal.metrics = [item.key]
}
or with simply these lines:
if goal.metrics == nil {
goal.metrics = []
}
goal.metrics?.append(item.key)

How to create a generic array with multiple models in Swift?

I am trying to create a generic array with different models. I have a parser method like that. But it doesn't work because it returns [Any] and it's not typesafe. I need to access my Movie and CastMember objects after parse method. I will use this array in my tableviewcontroller delegate methods. How can I do that?
static func parseSearchResult(_ data:Dictionary<String, AnyObject>) -> [Any] {
var array = [Any]()
let jsonData = JSON(data)
if let resultData = jsonData["results"].arrayObject {
let result = resultData as! [[String:AnyObject]]
for element in result {
if((element["media_type"]?.isEqual("person"))!){
let person = CastMember(json: element)
array.append(person)
}
else if((element["media_type"]?.isEqual("movie"))!){
let movie = Movie(json: element)
array.append(movie)
}
}
}
return array
}
and these are my structs
struct CastMember{
var id : Int?
var originalName : String?
var castName : String?
var picturePath : String?
init(json: [String:Any]){
originalName = json["name"] as? String
id = json["id"] as? Int
castName = json["character"] as? String
picturePath = "https://image.tmdb.org/t/p/w200/"
picturePath?.append((json["profile_path"] as? String) ?? "")
}
}
struct Movie{
var id : Int?
var title : String?
var imagePath : String?
init(json: [String:Any]){
title = json["title"] as? String
id = json["id"] as? Int
imagePath = "https://image.tmdb.org/t/p/w200/"
imagePath?.append((json["poster_path"] as? String)!)
}
}
Make your Movie and CastMember classes confirm to the protocol Codable.
also you will have to write a struct or class which matches the response data , like it must have an array of results and any other key coming in response.
struct ResponseModel<T> : Codable {
let results : [T]
}
then decode it like this :
let response : ResponseModel = JSONDecoder.decode(T.self)
You should make a protocol
Example:
enum MediaType {
case movie, castMember
}
protocol SearchResult {
var title: String { get }
var mediaType: MediaType { get }
}
struct SearchResultViewModel: SearchResult {
let title: String
let mediaType: MediaType
init(title: String, mediaType: MediaType) {
self.title = title
self.mediaType = mediaType
}
}
Then your parseSearchResult should return an array of [SearchResult] objects that conforms to the protocol, in this case, an array of SearchResultViewModel

Swift: display arrayobject to tableView

im trying to dispaly array object come from api response as [[String: Any]] at table view
and thats my struct
class CategoriesDep: NSObject {
var depName: String
var depImage: String
var subName = [subData]()
init?(dict: [String: JSON]) {
guard let image = dict["main_department_image"]?.imagePath, !image.isEmpty else { return nil }
self.depImage = image
self.depName = (dict["main_department_name"]?.string)!
}
struct subData {
var dep: String
init(dic: [String: Any]) {
self.dep = dic["sub_department_name"] as! String
}
}
}
Please check below code to parse your json
class CategoriesDep: NSObject {
var depName: String
var depImage: String
var subName = [subData]()
init?(dict: [String: Any]) {
guard let image = dict["main_department_image"] as? String, !image.isEmpty else { return nil }
self.depImage = image
self.depName = (dict["main_department_name"] as? String)!
subName = []
for subDict in (dict["sub_depart"] as? [[String:Any]] ?? []){
subName.append(subData(dic: subDict))
}
}
}
struct subData {
var dep: String
var image :String
var id : String
init(dic: [String: Any]) {
self.dep = dic["sub_department_name"] as! String
self.image = dic["sub_department_image"] as! String
self.id = dic["sub_department_id"] as! String
}
}
and if you want to access subdata struct out side of CategoriesDep class then declare structure outside CategoriesDep class
Parse your given json Respoise like
let json = [
[ "sub_depart" : [
[ "sub_department_name" : "hos", "sub_department_id" : "6", "sub_department_image" : "23.jpg"
]
],
"main_department_id" : "2",
"main_department_name" : "main ",
"main_department_image" : "14.jpg"
],
]
var catDepart : [CategoriesDep] = []
for dict in json {
catDepart.append(CategoriesDep(dict: dict)!)
}
print(catDepart[0].subName[0].dep)
You could use Codabel protocol to be more swifty ;) and cleaning up the code.
let jsonString = "[{\"sub_depart\" : [ {\"sub_department_name\" : \"hos\", \"sub_department_id\" : \"6\", \"sub_department_image\" : \"23.jpg\" } ], \"main_department_id\" : \"2\", \"main_department_name\" : \"main \", \"main_department_image\" : \"14.jpg\"}]"
struct CategoriesDep: Codable {
let mainDepartmentName: String
let mainDepartmentImage: String
let mainDepartmentId: String
var subDepart: [SubData] = []
}
struct SubData: Codable {
let subDepartmentName: String
let subDepartmentImage: String
let subDepartmentId: String
}
if let jsonData = jsonString.data(using: .utf8) {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
var departments: [CategoriesDep]? = try? decoder.decode([CategoriesDep].self, from: jsonData)
...
}
Note the decoder.keyDecodingStrategy = .convertFromSnakeCase here which is mapping the underscore (snake_case) API property names to your camelCase ones.
If you need different property names you have to implement CodingKeys enum to map them.
For more detailed information check this link.

my app is crashing and show this class is not key value coding-compliant for the key tableView using swift

This function gets variables from another file users.swift
append data
func getData(salval:String )
{ self.tabArray.removeAll()
ref = Database.database().reference()
let userID = Auth.auth().currentUser!.uid
if salval != "" {
ref?.child("Schedule").child("Codaphic").child(salval).child(userID).observe(.childAdded, with: { (snapshot)
in
if let dictionary = snapshot.value as? [String : AnyObject]
{
let user = users()
user.setValuesForKeys(dictionary)
self.tabArray.append(user)
self.tableView1.reloadData()
}
})
}
}
This is users.swift
import UIKit
class users : NSObject
{
var cname : String?
var _logi: String?
var key : String?
var wname : String?
var address : String?
var endtime : String?
var _leti : String?
var starttime : String?
var date : String?
var groupname : String?
var month : String?
}
this file is inherited with NSObject
but when project debugging its show error
If you're using user.setValuesForKeys(dictionary) it means that the variables in your User class MUST match the same names as the ones in your database. The safest way is to remove user.setValuesForKeys(dictionary) and use:
let user = User()
user.cname = dictionary["cname"] as? String
user.date = dictionary["data"] as? String
etc...

iOS - Save array of struct in CoreData

I have a struct like this:
     struct list
{
        
         var userId: Int = 0
         var id: Int = 0
         var title: String = ""
         var body: String = ""
}
In another part of my program, I declare an array of struct and I enter information through a JSON files downloaded from the internet.
var array = [list]()
Now my problem is to save and recuperar this array of struct in CoreData. I do not know how to go forward, would you give me a hand?
I think you best choice is to go with Binary Data type.
1.Create a toDictionary() method on your struct model:
func toDictionary() -> [String: Any] {
return ["userId: self.userId, "id": self.id, ...]
}
2.Then add a NSData property on your core data model, which represents your struct list:
#NSManaged var list: NSData?
3.Access that list property with a class helper:
func listDictionary() -> [String: Any]? {
guard let listData = self.list as? Data else { return nil }
let dict = NSKeyedUnarchiver.unarchiveObject(with: listData) as? [String: Any]
return dict
}
4.Create a fromDictionary() -> list on your list object which will build a model from dictionary

Resources