evermeer / AlamofireJsonToObjects

An Alamofire extension which converts JSON response data into swift objects using EVReflection
Other
161 stars 28 forks source link

Generic list parse #4

Closed sagits closed 9 years ago

sagits commented 9 years ago

Hi, im trying to parse a generic list, i think that there is no support for it for now, but is there any way i can use setValue forUndefinedKey function to pass a class type and be able to parse the list? Maybe is there another way? Thanks in advance.

What i have now:

class JsonMessage : EVObject {
  var _meta : MetaModel

  override
  init() {
      _meta = MetaModel()
  }
} 

class JsonMessageList<T> : JsonMessage {
  var records = [T]()

  override
  init() {

  }

}
   Alamofire.request(.GET, URL, headers: headers)
            .responseObject { (response: JsonMessageList<ProductModel>?, error: NSError?) in
               if (error == nil && response != nil) {
                   for product in response!.records {
                       println("id: " + product.name!);
                   }
                }
                else {
                    println("Error on request");
                }
            }

Im an Android Developer, and i have created a lib that does this on android. I pass a Model.class (Class) to a ListHelperModel and use this list as a type for gson (a google library that parse json to objects) to parse the list.

Take a look if you want:

ListHelperModel

Check getList() method

Unfortunelly im very new to swift/ios, so i just dont know how and if i can reproduce this.

evermeer commented 9 years ago

indeed you have to use the setValue forUndefinedKey. here is a unit test that will show you how to use generics: https://github.com/evermeer/EVReflection/blob/68edace301602dd43181075c604a1f987185be3f/EVReflection/EVReflectionTests/WorkaroundSwiftGenericsTests.swift#L16-46 And to make that work, you have to add the EVGenericsKVC protocol after your class definition

sagits commented 9 years ago

Thank you, it worked, but the [T] was not being detected as a [ProductModel]. A have been able to cast a single T to a Object, but not [T] to [Objects], example:

           //var list = response!.records as! [ProductModel]! this wont work, as ProductModel is not a U

           var list = response!.records as [U]!

            for product in list {
                var products : [ProductModel] = [ProductModel]();

                var p = product as! ProductModel
                products.append(p)
                println(product is ProductModel)
                println("id: " + p.name!);
            }

Is there a way to cast the entire list (sorry for asking, but i really cant found anything about it)? By the way, i'm trying to archieve this pattern:

ViewController:

    var c : CallListListener<ProductModel> = CallListListener<ProductModel>()
    GenericDao<ProductModel>().getAll(c);

GenericDao

  Alamofire.request(method, serverUrl + URL, headers: getHeaders())
      .responseObject {
          (response: JsonMessageList<U>?, error: NSError?) in

Thanks in advance.

evermeer commented 9 years ago

Ah, this could be 2 things.

  1. a generic array is of type Any and not AnyObject or NSObject. Then you should implement something like this: https://github.com/evermeer/EVReflection/blob/bb630dfb7759f3269ad872ba9e01b133d7b8e67c/EVReflection/EVReflectionTests/WorkaroundsTests.swift#L83-97
  2. in the setValue forUndefinedKey you will receive an array of dictionaries. So instead of assigning and casting it directly, you have to map it to your objects like this: array = (value as! NSArray).map({T(dictionary:$0)})

At the moment I can't create a sample for you. I will have a look at it tomorrow.

evermeer commented 9 years ago

I was wrong. It should just work. I created a new unit test that shows this. Here it is: https://github.com/evermeer/EVReflection/blob/c0de1d56f2589df7c0650a33ddb06b539a116d2b/EVReflection/EVReflectionTests/WorkaroundSwiftGenericsTests.swift#L25-35

In your json, do you have a root object with the property records which will contain an array of your product model records? So something like this: {"records":[{"property":"value"},{"property":"value2"}]} Or is the root of the json already an array? like this: [{"property":"value"},{"property":"value2"}] If so, then you need to use .responseArray instead of .responseObject

sagits commented 9 years ago

Thank you for your time man, now its working, My json was an object with an array inside. But i'm ashamed too say that my error was not typing records:

 var records = [T]()

Should be:

    var records : [T] = [T]()

My mistake, sorry. And just for helping others: Appcode will not convert your T objects to the actual model type (it will not autocomplete, but if you type list[0].someproperty it will work).

evermeer commented 9 years ago

Great that I could be of help. And now there are more unit tests that show how it should work. And we know that it does work. So no problem!