Manually mapping an object using AlamoFireObjectMapper - swift

I'm trying to write some unit tests and need a way to make a dummy version of an object that is mappable. For example:
class MyClassJsonResponse: Mappable {
var status: String?
var response: String?
var errorCode: SAErrorCode?
init() {
}
required init?(_ map: Map) {
}
func mapping(map: Map) {
status <- map["status"]
response <- map["response"]
errorCode <- (map["error_code"], SAErrorCodeTransform())
}
}
Usually this is returned from an Alamofire call, but how would I manually create one and manually pass in an empty JSON string? Any advice on this would be greatly appreciated! Thanks!

The object mapper defines an init function for your classes that allows you to pass a JSON dictionary object. In your test init a JSON object from a string and use that:
let json = JSON.parse("{}")
if let _json = json.dictionaryObject {
if let someObject = SomeObject(JSON: _json) {
// Some assertions here
}
else {
// Some assertions here about failure to map object, etc.
}
}
In my case I'm using this in a QuickSpec and importing SwiftyJSON, but should work in regular XCTest cases.

You can simply use the functions written in Mappable.swift that your class implements
public init?(JSON: [String: Any], context: MapContext? = nil)
public init?(JSONString: String, context: MapContext? = nil)
Inside these functions you will find this code:
if let obj: Self = Mapper(context: context).map(JSON: JSON) {...}
So theoretically you can pass whatever data you want through these functions to test the mapping.

Related

How do I get the value of a Published<String> in swift without using debugDescription?

I've got the following code, that runs in a playground.
I'm attempting to allow subscript access to #Published variables in a class.
The only way I've found so far to retrieve the String value in the below implementation of
getStringValue
is to use the debugDescription, and pull it out -- I've looked at the interface for Published, but can't find any way to retrieve the value in a func like getStringValue
Any pointers would be greatly appreciated :)
Edited to include an example of how it works with a non-published variable.
Cheers
import Foundation
import Combine
protocol PropertyReflectable {}
extension PropertyReflectable {
subscript(key: String) -> Any? {
return Mirror(reflecting: self).children.first { $0.label == key }?.value
}
}
class Foo : PropertyReflectable {
#Published var str: String = "bar"
var str2: String = "bar2"
}
// it seems like there should be a way to get the Published value without using debugDescription
func getStringValue(_ obj: Combine.Published<String>?) -> String? {
if obj == nil { return nil }
let components = obj.debugDescription.components(separatedBy: "\"")
return components[1]
}
let f = Foo()
let str = getStringValue(f["_str"] as? Published<String>)
print("got str: \(str!)")
// str == "bar" as expected
let str2 = f["str2"]!
print("got non-published string easily: \(str2)")
Published seems to be steeped in some compiler magic, for lack of a better wording, since it can only be used as a property wrapper inside classes.
That being said, would something like this work?
final class PublishedExtractor<T> {
#Published var value: T
init(_ wrapper: Published<T>) {
_value = wrapper
}
}
func extractValue<T>(_ published: Published<T>) -> T {
return PublishedExtractor(published).value
}

how to get element type for array in swift

Firstly there is a base class be called BaseModel ,below is the code:
class BaseModel : NSObject
{
var code:Int?
var message:Any?
public func setDictionaryToAttributes(dictionary_is dictionary:Dictionary<String,Any>?)->Bool
{
guard let dic:Dictionary<String,Any> = dictionary else {return false}
for (key,value) in dic {
let someType = type(of: value)
debugPrint("\(String(describing: someType.self))")
debugPrint("\(String(describing: someType))")
if someType is Array<Any>.Type { //i can't get TestListItemModel string
debugPrint("\(String(describing: someType))")
}
}
self.setValuesForKeys(dic)
return true;
}
}//class BaseModel end
and there is another class inherited from BaseModel
class TestListModel: BaseModel {
var tatalink:Any?
var items:Array<TestListItemModel>?
func setValuesFrom(jsonData j:JSON) { //j is a swifyJson object
guard var dic = j.dictionaryObject else {return}
if self.setDictionaryToAttributes(dictionary_is: dic)==false {
return
}
}
}
there is a class TestListItemModel for submodel in TestListModel
class TestListItemModel:BaseModel {
var imgurl: Any?
var title: Any?
}
Question is:
I want to automatically parse all attribute values in the BaseModel class from json data.
in func analysetDictionaryToAttributes: I can find which one is Array, but I don't know how to get this type and Continue to call it's analysetDictionaryToAttributes func.
Why do you expect to get TestListItemModel in your BaseModel class function. First of all I cannot see any structure having TestListItemModel. Because I can see you are just passing json dictionary object which is unaware of your class 'TestListItemModel' in this line
self.setDictionaryToAttributes(dictionary_is: dic)
Then why do you expect that parent class will know about its child class here is TestListItemModel and TestListModel.
So in this function
public func setDictionaryToAttributes(dictionary_is dictionary:Dictionary<String,Any>?)->Bool
you will always get Dictionary of String as a key and Value as Any type. And if you are expecting String then you can always check it this way
if value = value as String
{
print(value)
}

How would i create a universal return type in swift?

say I want to create a function in one of my structures that can take in a string, int, or any type as type, and i want to return the thing i get back based on the type param i pass in wether it be int string or whatever, how would I do that? I've tried this, but it doesn't seem to work, the call works but the program crashes when i try to return the value
static func getAny(type: Any, key: String) -> Any? {return data.value(forKey: key) as Any}
For the example you described:
class MyClasss {
static let data = UserDefaults.standard
static func get<Type>(key: String) -> Type? {
return data.value(forKey: key) as? Type
}
}
let string = MyClasss.get(key: "stringKey") as String?
let int: Int? = MyClasss.get(key: "intKey")
If you are just trying to find a clean way to get and set variables from UserDefaults. This is the way I personally like to do it in my projects.
class ApiStorage {
static var token : String? {
get {
return UserDefaults.standard.string(forKey: "bearerToken")
}
set {
UserDefaults.standard.set(newValue, forKey: "bearerToken")
}
}
}
Then to access UserDefaults it is as simple as
var token = ApiStorage.token
Or to write to UserDefaults it is as simple as
ApiStorage.token = "AUTHTOKEN"

Swift Realm - Creating child Realm objects and linking them to their parent

I am currently learning Realm and am converting my experimental app/game which uses arrays to Realm;
It loads pre-seeding data via a local JSON file and ObjectMapper; then creates objects in realm; this part seems to work.
// Parse response
let json = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! Array<Dictionary<String, AnyObject>>
let factories = Mapper<Factory>().mapArray(JSONArray: json)!
do {
let realm = try Realm()
try realm.write {
for factory in factories
{
realm.add(factory, update: true)
}
}
} catch let error as NSError {
print(error.localizedDescription as Any)
}
The issue I'm having is that when it maps; I'd like it to create its child objects at the same time and link them to parent.
Each parent (Factory) has about between 4 children (Engine) linked to it.
// Factory is parent object
class Factory: Object, Mappable {
dynamic var name: String = ""
let engines = List<Engine>()
//Impl. of Mappable protocol
required convenience init?(map: Map) {
self.init()
}
// Mappable
func mapping(map: Map) {
name <- map["name"]
}
}
// Engine is a child to Factory
class Engine: Object {
dynamic var production: Int = 0
// create children and add to the parent factory
static func createEngines(parent:Factory) -> [Engines]
{
var engines:[Engine] = [Engine]()
for _ in stride(from:0, to: 3, by: 1) {
//let engine : Engine = Engine.init(parent: element)
//engines.append(engine)
}
return engines
}
}
If I attempt to put this in my mappable
engines = Engine.createEngines(parent: self)
and make a change in my Factory model;
`var engines = List<Engine>()`
I get this error:
Cannot assign value of type '[Engine]?' to type 'List<Engine>'
The problem here is that simply creating an array of engines (children), appending it to an array doesn't seem to work with Realm and I'm not sure how to do this.
Hence, my question is how do I bulk create children, assign it to a given parent and add it to the current realm write/save?
Many thanks.
I changed my code to do this;
Read all the factories from JSON
Loop through the factories, creating engines
Link the parent object up.
I'm not sure if I did it right but it seems to be working.
I just don't like how I'm having to hardwire the parent; as I thought Realm/ObjectMapper could do that for me. But its not a major issue as there is only about 3 or 4 relationships.
let factories = Mapper<Factory>().mapArray(JSONArray: json)!
do {
let realm = try Realm()
try realm.write {
for f in factories
{
realm.add(f, update: true)
}
let factories = realm.objects(Factory.self)
print (factories.count) // for debug purposes
for f in factories {
for _ in stride(from: 0, to: f.qty, by: 1) {
let engine : Engine = Engine.init()
engine.parent = f
f.engines.append(engine)
}
}
}
} catch let error as NSError {
print(error.localizedDescription as Any)
}
This above code seems to do the work for me; although I do wish I didn't have to manually set the parent (engine.parent = f)
Anyhow, I've accepted #BogdanFarca's answer.
There is a very nice solution by Jerrot here on Githib Gist
The mapping should be defined in your main model object like this:
func mapping(map: Map) {
title <- map["title"]
products <- (map["products"], ArrayTransform<ProductModel>())
}
The real magic is happening in the ArrayTransform class:
func transformFromJSON(value: AnyObject?) -> List<T>? {
var result = List<T>()
if let tempArr = value as! Array<AnyObject>? {
for entry in tempArr {
let mapper = Mapper<T>()
let model : T = mapper.map(entry)!
result.append(model)
}
}
return result
}

How to call a class method in a convenience initializer in Swift

I am trying to consume an API where every object names its ID field differently. Example: Group.groupid, Team.teamid, etc.
I have a BaseAPIObject that has a required initializer that accepts a parsed JSON dictionary and a convenience initializer that takes just the ID field (the only required property of my class).
I've dealt with the changing id field names by adding a static aka "class" method that returns the ID field name and subclasses override that function to return their own field name.
The problem I have is that in my base class' convenience initializer I can't call self.dynamicType before I've called self.init() but I need the results of that static class function before I can properly construct my object.
public class BaseAPIObject {
var apiID: String!
var name: String?
var createdBy: String?
var updatedBy: String?
//Construct from JSONSerialization Dictionary
required public init(_ data: [String: AnyObject]) {
name = data["name"] as String?
createdBy = data["created_by"] as String?
updatedBy = data["updated_by"] as String?
super.init()
let idName = self.dynamicType.idFieldName()
apiID = data[idName] as String?
}
/// Creates an empty shell object with only the apiID set.
/// Useful for when you have to chase down a nested object structure
public convenience init(id: String) {
// THIS is what breaks! I can't call self.dynamicType here
// How else can I call the STATIC CLASS method?
// in ObjC this would be as simple as self.class.getIdFieldName()
let idFieldName = self.dynamicType.getIdFieldName()
let data = [idFieldName: id]
self.init(data)
}
//This gets overridden by subclasses to return "groupid" or whatever
class func idFieldName() -> String {
return "id"
}
}
Question: How can I solve the problem of calling a subclass' class function before I run init on the instance itself?
Instead of creating a class function for figuring out the id, create init functions instead. Since you already have to create one of these functions per subclass, you're not really losing anything. The subclasses init function then calls the super's init with the id name.
Here's an example, I changed some of the properties of your group just for the sake of making the example simple to illustrate the concept.
public class BaseAPIObject {
var objData: [String:String]
required public init(_ data: [String: String]) {
println("Data: \(data)")
self.objData = data
}
public convenience init(id: String, idFieldName: String) {
let data = [idFieldName: id]
self.init(data)
}
}
And then in your subclass, just conceptually something like this:
public class GroupObject: BaseAPIObject {
public convenience init (id: String) {
self.init(id: id, idFieldName: "group")
}
}
let go = GroupObject(id: "foo")
println(go.objData["group"]!) //prints "foo"