Search code examples
iosjsonswiftresponsealamofire

AlamofireObjectMapper getting nil when it should give me value


I'm so frustrated, because I want to map JSON to Swift objects, I tried like 5 libraries and every time the f****** Swift is giving me nil.

So let's take the Instagram API making simple request to get user data by suppling:

user-id: 237965875
client_id: b806368aaf384a7baec491f8fab610a6

I'm using:

Podfile

platform :ios, ‘9.0’ use_frameworks!

target ‘secondTest’ do pod 'AlamofireObjectMapper’, ‘~> 1.0’ end

and

XCODE 7
Swift 2.0
AlamofireObjectMapper v1.0

I know that I need to create swift file (class) and define the object that should handle the response:

the response is: (got it from apigee.com)

HTTP/1.1 200 OK
Content-Language:
en
X-Ratelimit-Limit:
5000
Vary:
Cookie, Accept-Language, Accept-Encoding
Date:
Sun, 27 Sep 2015 18:46:45 GMT
Content-Length:
383
Expires:
Sat, 01 Jan 2000 00:00:00 GMT
X-Ratelimit-Remaining:
4987
Set-Cookie:
csrftoken=41681b429002fa50331def50b07b2a78; expires=Sun, 25-Sep-2016 18:46:45 GMT; Max-Age=31449600; Path=/
Connection:
keep-alive
Content-Type:
application/json; charset=utf-8
Server:
Apigee Router
Cache-Control:
private, no-cache, no-store, must-revalidate
Pragma:
no-cache

    {
      "meta":  
      {
        "code": 200
      },
      "data":  
      {
        "username": "jessica_brti",
        "bio": "I write and make silly faces for a living.",
        "website": "http://www.wattpad.com/JessicaBrti",
        "profile_picture": "https://igcdn-photos-f-a.akamaihd.net/hphotos-ak-xfa1/t51.2885-19/11311247_1206483099369077_1549111893_a.jpg",
        "full_name": "Jessy",
        "counts":
        {
          "media": 50,
          "followed_by": 55153,
          "follows": 46
        },
        "id": "237965875"
      }
    }

then my swift class file that defines the object to handle this response is:

import Foundation
import ObjectMapper

    class instaResponse: Mappable
    {
        var metas: [meta]?
        var datas: [data]?

        required init?(_ map: Map){}

        func mapping(map: Map) {
            metas <- map["meta"]
            datas <- map["data"]
        }
    }

    class meta: Mappable
    {
        var code: String?

        required init?(_ map: Map){}

        func mapping(map: Map)
        {
            code <- map["code"]
        }
    }

    class data: Mappable {
        var username: String?
        var bio: String?
        var website: String?
        var profile_picture: String?
        var full_name: String?
        var countss: [counts]?
        var id: String?

        required init?(_ map: Map){}

        func mapping(map: Map)
        {
            username <- map["username"]
            bio <- map["bio"]
            website <- map["website"]
            profile_picture <- map["profile_picture"]
            full_name <- map["full_name"]
            countss <- map["counts"]
            id  <- map["id"]
        }
    }

    class counts: Mappable {
        var media: Int?
        var followed_by: Int?
        var follows: Int?

        required init?(_ map: Map){}

        func mapping(map: Map)
        {
            media <- map["media"]
            followed_by <- map["followed_by"]
            follows <- map["follows"]
        }
    }

And finally this is the file where I make the request and parsing the JSON as object

import UIKit
import Alamofire
import AlamofireObjectMapper
import ObjectMapper

    class ViewController: UIViewController {

        override func viewDidLoad() {

            let userID =
            [
                "user-id":"237965875",
                "client_id":"b806368aaf384a7baec491f8fab610a6"
            ]

            let URL = "https://api.instagram.com/v1/users/237965875"

            Alamofire.request(.GET, URL, parameters: userID)
                .validate()
                .responseObject
                {
                    (result: instaResponse?, error: ErrorType?) in

                    print(error.debugDescription)

                    if let data = result?.datas
                    {
                        for i in data
                        {
                            print(i.username)
                        }
                    }
                }.responseJSON{(_,_,result) in

                    print(result.value)
            }

            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
        }

        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }

    }

And at the end, I'm getting for the printed username

"print(i.username)"

JUST ONE BIG

nil

and the second print

"print(result.value)"

is giving the shiny:

Optional({
data =     {
    bio = "I write and make silly faces for a living.";
    counts =         {
        "followed_by" = 55153;
        follows = 46;
        media = 50;
    };
    "full_name" = Jessy;
    id = 237965875;
    "profile_picture" = "https://scontent.cdninstagram.com/hphotos-xfa1/t51.2885-19/11311247_1206483099369077_1549111893_a.jpg";
    username = "jessica_brti";
    website = "http://www.wattpad.com/JessicaBrti";
};
meta =     {
    code = 200;
};
})

But i do not know how to make the object just witn Alamofire.

So guys , anyone please help me to solve this puzzle.

Thanks in Advance !!!


Solution

  • Your problem is that the meta and data elements in your JSON are just objects, they are not arrays of objects. Because your mapping maps these keys to arrays, they are unable to be deserialized.

    Your mapping class should be

    import Foundation
    import ObjectMapper
    
        class instaResponse: Mappable
        {
            var metas: meta?
            var datas: data?
    
            required init?(_ map: Map){}
    
            func mapping(map: Map) {
                metas <- map["meta"]
                datas <- map["data"]
            }
        }
    
    ...
    

    And then you don't need the for loop to access the data -

    print(error.debugDescription)
    
    if let data = result?.datas {
        print(data.username)
    }