简体   繁体   中英

How to parse NSDictionary Data

My app currently is using Yelp Service API and returns key value pairs of associated data that the yelp client provides. My scenario is that I have an Attractions view controller which drops pin annotations of different categories, ie 'Asian Food', etc. When you click on the pin annotation and hit the callout it takes you to a Detail View Controller.

Here is where I do that:

func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
        if (control == view.rightCalloutAccessoryView) {
            let selectedLocation = view.annotation;
            let selectedCoordinate = view.annotation.coordinate;
            var latitude = selectedCoordinate.latitude
            var longitude = selectedCoordinate.longitude
            var location:CLLocation = CLLocation(latitude: latitude, longitude: longitude)
            let businessPlacemark = MKPlacemark(coordinate: selectedCoordinate, addressDictionary: nil)
            indicatedMapItem = selectedCoordinate;
            performSegueWithIdentifier("attractionToDetail", sender: self);
        }
    }
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        var attractionsDetailViewController:AttractionsDetailViewController = segue.destinationViewController as! AttractionsDetailViewController
        attractionsDetailViewController.attractionLocation = indicatedMapItem;
    }

And here is my API service call:

class func searchWithQueryWithRadius(map: MKMapView, term: String, deal: Bool, radius: Int, sort: Int, categories: String, completion: ([Resturant]!, NSError!) -> Void) {
        YelpClient.sharedInstance.searchWithTerm(term, deal: false, radius: radius, sort: sort,categories: categories, success: { (operation: AFHTTPRequestOperation!, response: AnyObject!) -> Void in
            let responseInfo = response as! NSDictionary
            resultQueryDictionary = responseInfo
            println(responseInfo)
            let dataArray = responseInfo["businesses"] as! NSArray
            for business in dataArray {
                let obj = business as! NSDictionary
                var yelpBusinessMock: YelpBusiness = YelpBusiness(dictionary: obj)
                var annotation = MKPointAnnotation()
                annotation.coordinate = yelpBusinessMock.location.coordinate
                annotation.title = yelpBusinessMock.name
                map.addAnnotation(annotation)
            }
            }) { (operation: AFHTTPRequestOperation!, error: NSError!) -> Void in
            println(error)
        }
    }

This prints to the logs data like this when I query for Asian Food in the Seattle area:

{
businesses =     (
            {
        categories =             (
                            (
                Korean,
                korean
            ),
                            (
                Buffets,
                buffets
            )
        );
        "display_phone" = "+1-206-854-3166";
        distance = "124.9692597772704";
        id = "ummas-lunch-box-seattle";
        "image_url" = "http://s3-media2.fl.yelpcdn.com/bphoto/QqrpImnPywZ9zc721RVRrg/ms.jpg";
        "is_claimed" = 1;
        "is_closed" = 0;
        location =             {
            address =                 (
                "1301 5th Ave",
                Concourse
            );
            city = Seattle;
            coordinate =                 {
                latitude = "47.6088937";
                longitude = "-122.3342613";
            };
            "country_code" = US;
            "cross_streets" = "Union St & University St";
            "display_address" =                 (
                "1301 5th Ave",
                Concourse,
                Downtown,
                "Seattle, WA 98101"
            );
            "geo_accuracy" = "9.5";
            neighborhoods =                 (
                Downtown
            );
            "postal_code" = 98101;
            "state_code" = WA;
        };
        "mobile_url" = "http://m.yelp.com/biz/ummas-lunch-box-seattle";
        name = "Umma's Lunch Box";
        phone = 2068543166;
        rating = "4.5";
        "rating_img_url" = "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/99493c12711e/ico/stars/v1/stars_4_half.png";
        "rating_img_url_large" = "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/9f83790ff7f6/ico/stars/v1/stars_large_4_half.png";
        "rating_img_url_small" = "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/a5221e66bc70/ico/stars/v1/stars_small_4_half.png";
        "review_count" = 155;
        "snippet_image_url" = "http://s3-media1.fl.yelpcdn.com/photo/H1UEaGpAztTzFIDKbsx_UA/ms.jpg";
        "snippet_text" = "Korean comfort food at an affordable price. My only wish is that they are opened longer..\n\nI'm sure that everybody here has already written about it, but it...";
        url = "http://www.yelp.com/biz/ummas-lunch-box-seattle";
    }

What I want to do is simply extract the yelp response data and set the AddressLabel text I have in my DetailViewController to the address from the Yelp Data(As reverseGeoCoding has minor bugs).

Currently i'm using this YelpBusiness.swift that I created, but i'm not sure if it's correct...

var dictionary: NSDictionary


init(dictionary: NSDictionary) {
    self.dictionary = dictionary
}

var business: String {
    get {
        return self.dictionary["businesses"] as! String
    }
}

var name: String {
    get {
        return self.dictionary["name"] as! String
    }
}

var phone: String {
    get {
        return self.dictionary["phone"] as! String
    }
}

var rating: String {
    get {
        return self.dictionary["rating"] as! String
    }
}

var imageURL: NSURL? {
    get {
        if let image = self.dictionary["image_url"] as? String {
            return NSURL(string: image.stringByReplacingOccurrencesOfString("ms.jpg", withString: "ls.jpg", options: nil, range: nil))
        }
        return nil
    }
}

var ratingImageURL: NSURL {
    get {
        return NSURL(string: self.dictionary["rating_img_url_large"] as! String)!
    }
}

var reviewCount: Int {
    get {
        return self.dictionary["review_count"] as! Int
    }
}

var deals: Array<AnyObject>? {
    get {
        if let deals = self.dictionary["deals"] as? Array<AnyObject> {
            return deals
        }
        return nil
    }
}

var latitude: Double? {
    get {
        if let location = self.dictionary["location"] as? NSDictionary {
            if let coordinate = location["coordinate"] as? NSDictionary {
                return (coordinate["latitude"] as! Double)
            }
        }
        return nil
    }
}

var longitude: Double? {
    get {
        if let location = self.dictionary["location"] as? NSDictionary {
            if let coordinate = location["coordinate"] as? NSDictionary {
                return (coordinate["longitude"] as! Double)
            }
        }
        return nil
    }
}

var location: CLLocation {
    get {
        return CLLocation(latitude: self.latitude!, longitude: self.longitude!)
    }
}

var shortAddress: String {
    get {
        if let location = self.dictionary["location"] as? NSDictionary {
            if let address = location["address"] as? Array<String> {
                if let neighborhoods = location["neighborhoods"] as? Array<String> {
                    return ", ".join(address + [neighborhoods[0]])
                }
                return ", ".join(address)
            }
        }
        return ""
    }
}

var displayAddress: String {
    get {
        if let location = self.dictionary["location"] as? NSDictionary {
            if let address = location["display_address"] as? Array<String> {
                return ", ".join(address)
            }
        }
        return ""
    }
}

var displayCategories: String {
    get {
        if let categories = self.dictionary["categories"] as? Array<Array<String>> {
            return ", ".join(categories.map({ $0[0] }))
        }
        return ""
    }
}

Thanks!

NEW ANSWER

Because you're using NSDictionary & NSArray objects, you can use the magical valueForKeyPath:

// I HIGHLY recommend a more descriptive variable name instead of "obj"
let obj = business as! NSDictionary 
let displayAddressArray = obj.valueForKeyPath("location.display_address") as NSArray

if displayAddressArray.count > 0
{
    annotation.title = "\(displayAddressArray[0])\n\(displayAddressArray[1])\n"
}

You probably can reformat how the annotation looks depending on what you want it to look like.

More information about this, plus native swift nested dictionary access, can be found in this helpful article I was just looking at .

ORIGINAL ANSWER

If I understand your question correctly, and assuming the YelpBusiness object matches what I see in this github repo , what you need to do might be as easy as something like changing this line:

annotation.title = yelpBusinessMock.name

to:

annotation.title = yelpBusinessMock.location.display_address

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM