Creating new instance of object implementing Mappable interface - swift

I am using ObjectMapper library to convert my model objects (classes and structs) to and from JSON.
But sometimes I would like to create objects without JSON.
Supposse, I have class like this:
class User: Mappable {
var username: String?
var age: Int?
required init?(map: Map) {
}
func mapping(map: Map) {
username <- map["username"]
age <- map["age"]
}
}
I would like to create object without JSON, like this:
let newUser = User(username: "john", age: 18)
Is creating objects in this way possible for class implementing Mappable?

Add another init method with username and age as parameters.
class User: Mappable {
var username: String?
var age: Int?
init(username:String, age:Int) {
self.username = username
self.age = age
}
required init?(map: Map) {
}
func mapping(map: Map) {
username <- map["username"]
age <- map["age"]
}
}
And use it like this.
let user = User(username: "hello", age: 34)

Related

How to destructure variable into function's parameter?

How can I pass the value of all key from object as functions parameters? like python did.
I have one function getNameInfo with parameter with default value firstName, lastName, age and one object with key firstName, lastName, age how is the best way for me to descture the pbject and pass all value of key into function? in python i can do something like getNameInfo(**a.__dict__.values()) but
class Person {
public var firstName = "firstName"
public var lastName = "lastName"
public var age = 12
public init(firstName: String, lastName: String, age: Int){
self.firstName = firstName
self.lastName = lastName
self.age = age
}
}
let a = Person(firstName: "firstName", lastName: "lastName", age: 12)
func getNameInfo(firstName: String = "i am first", lastName: String = "I am lat", age: Int = 50) {
print("\(fName), \(lName), \(age)")
}
getNameInfo()
// getNameInfo(a) // expect to print out firstName, lastName, 12
There is no similar feature in Swift. The closest version is to use protocols:
protocol NameInfoProviding {
var firstName: String { get }
var lastName: String { get }
var age: Int { get }
}
extension Person: NameInfoProviding {}
func getNameInfo(_ nameInfo: some NameInfoProviding) {
print("\(nameInfo.firstName), \(nameInfo.lastName), \(nameInfo.age)")
}
getNameInfo(a)
But yes, this is a different feature and used in different ways.

Create an object array with few object properties of another object array using map

Suppose we have an Employee class like this
class Employee {
var id: String?
var name: String?
var role: String?
var age: Int?
var salary: Int?
}
var employeeList: [Employee]
I have to create a new object array with just few properties(eg: id, name, age) from employeeList.
Is there any other way(like map) other than using a for-loop to iterate the employeeList?
If you wanted to use map, you could do something like the following:
class Employee {
var id: String?
var name: String?
var role: String?
var age: Int?
var salary: Int?
}
var employeeList: [Employee]
var employeeModifiedList = employeeList.map {
(id: $0.id, name: $0.name, age: $0.age)
}
Something like this?
let myData: [(String?, String?, Int?)] = employeeList.map { ($0.id, $0.name, $0.age) }
Although not sure why your id is String type... usually ID's are Int

Using Object Mapping with Kinvey

I have an array of objects I'm trying to get out of one of my collections. I've followed along using their docs and also some Googling and I believe I'm close to the solution, however not close enough. Here's what I have:
class Clothing: Entity {
var categories: [Category]!
var gender: String!
override class func collectionName() -> String {
//return the name of the backend collection corresponding to this entity
return "categories"
}
override func propertyMapping(_ map: Map) {
super.propertyMapping(map)
categories <- map["clothing"]
gender <- map["gender"]
}
}
class Category: NSObject, Mappable{
var title: String?
var image: String?
convenience required init?(map: Map) {
self.init()
}
func mapping(map: Map) {
title <- map["category"]
image <- map["image"]
}
}
I'm able to get the right gender, but the array of categories doesn't seem to get mapped to the Category object. Any thoughts?
your model actually have one issue, as you can see at https://devcenter.kinvey.com/ios/guides/datastore#Model you should use let categories = List<Category>() instead of var categories: [Category]!. Here's the model that and test and worked:
import Kinvey
class Clothing: Entity {
let categories = List<Category>()
var gender: String!
override class func collectionName() -> String {
//return the name of the backend collection corresponding to this entity
return "clothing"
}
override func propertyMapping(_ map: Map) {
super.propertyMapping(map)
categories <- ("categories", map["categories"])
gender <- ("gender", map["gender"])
}
}
class Category: Object, Mappable{
var title: String?
var image: String?
convenience required init?(map: Map) {
self.init()
}
func mapping(map: Map) {
title <- ("category", map["category"])
image <- ("image", map["image"])
}
}
and here's a sample code how to save a new Clothing object
let casualCategory = Category()
casualCategory.title = "Casual"
let shirtCategory = Category()
shirtCategory.title = "Shirt"
let clothing = Clothing()
clothing.gender = "male"
clothing.categories.append(shirtCategory)
clothing.categories.append(casualCategory)
dataStore.save(clothing) { (result: Result<Clothing, Swift.Error>) in
switch result {
case .success(let clothing):
print(clothing)
case .failure(let error):
print(error)
}
}

Using AlamofireObjectMapper Error

I'm using AlamofireObjectMapper to map object from JSON,But no response retrieved.Here is my code
let articleAPI = "https://news-at.zhihu.com/api/4/news/latest"
Alamofire.request(articleAPI).responseObject {(response: DataResponse<ArticleResponse>) in
let contents = response.result.value
print((contents?.stories?[0].title)!)
the ArticleResponse object looks like the following:
import ObjectMapper
class ArticleResponse: Mappable {
var date: String?
var stories: [ArticleDetailResponse]?
var top_stories: [TopStoriesResponse]?
required init?(map: Map) {
}
func mapping(map: Map) {
date <- map["date"]
stories <- map["stories"]
top_stories <- map["top_stories"]
}
}
class ArticleDetailResponse: Mappable {
var images: [String]?
var type: Int?
var id: Int?
var ga_prefix: String?
var title: String?
var multipic: Bool?
required init?(map: Map) {
}
func mapping(map: Map) {
images <- map["images"]
type <- map["type"]
id <- map["id"]
ga_prefix <- map["ga_prefix"]
title <- map["title"]
multipic <- map["multipic"]
}
}
class TopStoriesResponse: Mappable {
var image: String?
var type: Int?
var id: Int?
var ga_prefix: String?
var title: String?
required init?(map: Map) {
}
func mapping(map: Map) {
image <- map["image"]
type <- map["type"]
id <- map["id"]
ga_prefix <- map["ga_prefix"]
title <- map["title"]
}
}
I am doing this according the AlamofireObjectMapper usage document.In addition to that,Is there anything else have to implement?

Object Mapper making my values to optionals

struct User: Mappable {
init?(map: Map) {
}
mutating func mapping(map: Map) {
token <- map["token"]
email <- map["email"]
}
var token : String!
var email : String!
}
I'm declaring my strings as conditionally wrapped so that I can use directly with out wrapping, but after mapping all my strings to access I need to wrap again?
Why do need to wrap again?
You don't need the wrapping if you check the values in the initializer, something like this will work.
struct User: Mappable {
var token: String
var email: String
init?(map: Map) {
guard let token: String = map["token"].value(),
let email: String = map["email"].value() else {
print("User should have token and email")
return nil
}
self.token = token
self.email = email
}
mutating func mapping(map: Map) {
token <- map["token"]
email <- map["email"]
}
}
Now you can use token and email in your code without wrapping