iOS - Save array of struct in CoreData - ios

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

Related

Use of Array in a Struct in Swift

I have the following struct where I use string, Int, and Bool. I fill these variable when I query my products from Firestore. Now I do not know how to treat an array here in my struct:
struct Product {
var price: Int
var name: String
var isActive: Bool
//var categories: how do I call out the array here?
init(
price: Int,
name: String,
isActive: Bool,
//categories: how do I call out the array here?
){
self.price = price
self.name = name
self.isActive = isActive
//self.categories: how do I call out the array here?
}
init(data: [String: Any]){
price = data[DatabaseRef.price] as? Int ?? 0
name = data[DatabaseRef.name] as? String ?? ""
isActive = data[DatabaseRef.isActive] as? Bool ?? false
//categories: how do I call out the array here?
}
static func modelToData(product: Product) -> [String: Any] {
let data : [String: Any] = [
DatabaseRef.price : product.price,
DatabaseRef.name : product.name,
DatabaseRef.isActive : product.isActive,
//categories: how do I call out the array here?
]
return data
}
}
When I query my categories from my database; it would look like this:
categories = ["Fruits", "Vegetables", "Frozen"]
Not sure how I can call the categories out in each part of the struct I mentioned up here. Newbie alert!
You can declare an array like this.
var categories: [String] = []

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: how to convert a [String:Any] array to a specific array

I have this simple Struct:
protocol DocumentSerializable {
init?(dictionary:[String:Any])
}
struct Item {
var title:String
var text:String?
var dictionary:[String:Any] {
return [
"title":title,
"text":text,
]
}
}
extension Item : DocumentSerializable {
init?(dictionary: [String : Any]) {
guard let title = dictionary["title"] as? String,
let text = dictionary["text"] as? String? else {return nil}
self.init(title: title, text: text)
}
}
When I recive my json, I put it in an array...
if let array = result?.data as? Array<[String:Any]> {...
How can I convert this array into an array of Items? var itemsArray = [Item]()
The two arrays have exactly the same structure
Thanks
Use
struct Item :Decodable {
let title:String
let text:String?
}
//
do {
let root = try JSONDecoder().decode([Item].self, from:jsonData)
print(root)
}
catch {
print(error)
}
Use compactMap, it handles also the nil cases:
itemsArray = array.compactMap{ Item(dictionary: $0) }
However in Swift 4 it's highly recommended to use the Codable protocol

Generic Class with NSObject inheritance, self.setValue(, forKey: ) not work

I want to set value direct in NSObject using self.setValue(, forKey: ) that time give me an error. like that
2018-03-08 17:36:36.723485+0530 BaseProject[20631:312969] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<_TtGC11BaseProject8DataRootCS_4Root_ 0x600000452840> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key data.'
When I set the value using Generic T like var data: [T] = [] then app is crash, and I set Class name like var data: [Root] = [] then work perfectly.
My Codes is
protocol AGMappable {
init(with responseDict: [String: AnyObject])
}
My Model Class is
class Root: NSObject, AGMappable {
var avatar: String = ""
var id: Int = 0
var first_name: String = ""
var last_name: String = ""
required init(with responseDict: [String: AnyObject]) {
super.init()
avatar = responseDict["avatar"] as? String ?? ""
}
}
Set a value using setValue(,forKey:)
class DataRoot<T: AGMappable>: NSObject, AGMappable{
var page: Int = 0
var per_page: Int = 0
var total: Int = 0
var total_pages: Int = 0
var data: [T] = []
required init(with responseDict: [String: AnyObject]){
super.init()
if let datastr = responseDict["data"] as? [[String : AnyObject]] {
var temp: [T] = []
for v in datastr {
temp.append(T(with: v as [String: AnyObject]))
}
self.setValue(temp, forKey: "data") // Here error
}
}
}
setValue(_:forKey:) can work with #objc properties only, as it relies on runtime features that only #objc properties have. Swift 4 changed the way class members are available to Objective-C: they are no longer available by default, so you either need to declare the class as #objcMembers, or add #objc individually to every member you need to expose to Objective-C.
However in your case the class can't be exported to Objective-C due to the fact that is a generic one, so you need to declare data as #objc var data: [T] = [], or dynamic var data: [T] = []
You can rewrite it like this
let datastr = responseDict["data"] as? [[String : Any]]
self.data = datastr?.map {
T(with: $0)
} ?? [T]()

Casting struct to NSUserDefaults in Swift?

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")
}

Resources