Using AlamofireObjectMapper Error - swift

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?

Related

Unable to convert xml to object - Swift4

I have the following XML string. I am trying to parse with XMLMapper (3rd party library).
I need to create array of
The xml is as follow;
<RandomDecimals>
<decimal>98258979</decimal>
<decimal>1000002218</decimal>
<decimal>1000002102</decimal>
<decimal>1000005713</decimal>
<decimal>1000002035</decimal>
<decimal>1000001434</decimal>
<decimal>1000001066</decimal>
<decimal>1000001498</decimal>
<decimal>1000002313</decimal>
<decimal>1000016914</decimal>
<decimal>1000017021</decimal>
<decimal>1000019039</decimal>
<decimal>52373625</decimal>
</RandomDecimals>
The code to parse to object is as follows;
class DecimalElement: XMLMappable {
var nodeName: String!
var decimal: String?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
decimal <- map["decimal"]
}
}
class Response: XMLMappable {
var nodeName: String!
var shouldReset: Bool!
var randomDecimals: [DecimalElement]?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
randomDecimals <- map["RandomDecimals.decimal"]
shouldReset <- map["ShouldReset"]
}
As a summary, I need to take decimals into randomDecimals array. But the I need to do it with XMLMapper.
What am I doing wrong?
BR,
Erdem
If your XML looks something like this:
<root>
<ShouldReset>true</ShouldReset>
<RandomDecimals>
<decimal>98258979</decimal>
<decimal>1000002218</decimal>
<decimal>1000002102</decimal>
<decimal>1000005713</decimal>
<decimal>1000002035</decimal>
<decimal>1000001434</decimal>
<decimal>1000001066</decimal>
<decimal>1000001498</decimal>
<decimal>1000002313</decimal>
<decimal>1000016914</decimal>
<decimal>1000017021</decimal>
<decimal>1000019039</decimal>
<decimal>52373625</decimal>
</RandomDecimals>
</root>
then, you can solve your issue by replacing:
var randomDecimals: [DecimalElement]?
with:
var randomDecimals: [String]?
in your Response class.
class Response: XMLMappable {
var nodeName: String!
var shouldReset: Bool!
var randomDecimals: [String]?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
randomDecimals <- map["RandomDecimals.decimal"]
shouldReset <- map["ShouldReset"]
}
}
You can also use Array of Int64 to map directly the decimal numbers:
var randomDecimals: [Int64]?
Hope this helps.

Creating new instance of object implementing Mappable interface

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)

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

alamofire object mapper .. why print my project name?

Screenshot Here
Note: This is my first swift file
override func viewDidLoad() {
super.viewDidLoad()
let encodingURL = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
Alamofire.request(encodingURL!).responseObject { (response: DataResponse<channel>) in
let MovieResponse = response.result.value
print("결과: \(MovieResponse?.channel?.result as AnyObject)")
print("타이틀: \(MovieResponse?.channel?.title as AnyObject)")
print("토탈카운트: \(MovieResponse?.channel?.totalCount as AnyObject)")
print("전체:\(MovieResponse?.channel as AnyObject)")
print("아이템: \(MovieResponse?.channel?.item as AnyObject)")
print("배우:\(MovieResponse?.channel?.item.first?.actor as AnyObject)")
}
}
Note: second swift file
import Foundation
import ObjectMapper
class channel : Mappable {
var channel : channelComponents?
required init?(map: Map){ }
func mapping(map: Map) {
self.channel <- map["channel"]
}
}
class channelComponents : Mappable {
var totalCount : Int?
var result : Int?
var title : String?
var item : [item]
required init?(map: Map){
item = []
}
func mapping(map: Map) {
self.totalCount <- map["totalCount"]
self.result <- map["result"]
self.title <- map["q"]
self.item <- map["item"]
}
}
class item : Mappable {
var actor : [Actor]
required init?(map: Map) {
actor = []
}
func mapping(map: Map) {
self.actor <- map["actor"]
}
}
class Actor : Mappable {
var content : String?
var link : String?
required init?(map: Map) { }
func mapping(map: Map) {
self.content <- map["content"]
self.link <- (map["link"])
}
}
input
print("아이템: \(MovieResponse?.channel?.item as AnyObject)")
print("배우:\(MovieResponse?.channel?.item.first?.actor as AnyObject)")
output
아이템: (
"Movie_D.item"
)
배우:(
"Movie_D.Actor",
"Movie_D.Actor",
"Movie_D.Actor",
"Movie_D.Actor",
"Movie_D.Actor",
"Movie_D.Actor",
"Movie_D.Actor"
)
Movie_D is my project name.
I want to know the actor's name, but there is just my project name. (the count is right)
You should cast the actor property to a String (assuming it is one) to properly display the actor's name in your print statement.
print("배우:\(String(describing: MovieResponse?.channel?.item.first?.actor))")

Generic function to map JSON objects with ObjectMapper

I have a generic function:
func toObjectMapper<T: Mappable>(mapper: T, success: (result: Mappable) -> Void, failure: (error: NSError) -> Void){
let alomofireApiRequest = AlamofireApiRequest(apiRequest: self)
Alamofire.request(alomofireApiRequest)
.responseObject { (response: Response<T, NSError>) in
guard let value = response.result.value else {
failure(error: response.result.error!)
return
}
success(result: value)
}
}
And I want to call it like this:
public func login(login: String, password: String) -> UserResponse {
let params = ["email":login, "password":password]
let request = ApiRequest(method: .POST, path: "login", parameters: params)
request.toObjectMapper(UserResponse.self, success: { result in
print(result)
}, failure: { error in
print(error.description)
})
}
But I always get this error:
Cannot invoke 'toObjectMapper' with an argument list of type '(UserResponse.Type, success: (result: Mappable) -> Void, failure: (error: NSError) -> Void)'
This is my userResponse:
import Foundation
import ObjectMapper
import RealmSwift
public class UserResponse: Object, Mappable {
dynamic var id = 0
dynamic var name = ""
dynamic var address = ""
dynamic var zipcode = ""
dynamic var city = ""
dynamic var country = ""
dynamic var vat = ""
dynamic var email = ""
dynamic var created_at = NSDate()
dynamic var updated_at = NSDate()
override public static func primaryKey() -> String? {
return "id"
}
//Impl. of Mappable protocol
required convenience public init?(_ map: Map) {
self.init()
}
public func mapping(map: Map) {
id <- map["id"]
name <- map["name"]
address <- map["address"]
zipcode <- map["zipcode"]
city <- map["city"]
country <- map["country"]
vat <- map["vat"]
email <- map["email"]
created_at <- map["created_at"]
updated_at <- map["updated_at"]
}
}
Any help ?
I think the problem is that you are trying to use UserResponse as an instantiated object but using UserResponse.self is only the class type.
A solution is to make UserResonse a singleton (or just instantiate an instance before passing it to 'toObjectMapper' as an argument)
I don't know if this code specifically will work but it's along these lines:-
public class UserResponse: Object, Mappable {
dynamic var id = 0
dynamic var name = ""
dynamic var address = ""
dynamic var zipcode = ""
dynamic var city = ""
dynamic var country = ""
dynamic var vat = ""
dynamic var email = ""
dynamic var created_at = NSDate()
dynamic var updated_at = NSDate()
static let shared = UserResponse() //singleton instantiation
override public static func primaryKey() -> String? {
return "id"
}
//Impl. of Mappable protocol
required convenience public init?(_ map: Map) {
self.init()
}
public func mapping(map: Map) {
id <- map["id"]
name <- map["name"]
address <- map["address"]
zipcode <- map["zipcode"]
city <- map["city"]
country <- map["country"]
vat <- map["vat"]
email <- map["email"]
created_at <- map["created_at"]
updated_at <- map["updated_at"]
}
}
and then in your function call
public func login(login: String, password: String) -> UserResponse {
let params = ["email":login, "password":password]
let request = ApiRequest(method: .POST, path: "login", parameters: params)
request.toObjectMapper(UserResponse.shared, success: { result in
print(result)
}, failure: { error in
print(error.description)
})
}