Order an Array/Dictionary in objective c [duplicate] - ios

This question already has answers here:
How can I sort an NSArray containing NSDictionaries?
(3 answers)
Closed 8 years ago.
I am trying a little project where I get the current location coordinates, then by the current location I find coffee shops nearby and display them in a UITableView. So far I have managed to load the JSON script with the information, parse it into a dictionary, and display it in the UITableView. What I want to do now is try to order the information by 'distance' or by 'name' (alphabetically). How can I do that? Here is some code to show what I have done so far.
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
if (!self.didFindLocation) {
self.didFindLocation = YES;
[self.locationManager stopUpdatingLocation];
}
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
CLLocation *crnLoc = [locations lastObject];
NSString *latitudeString = [NSString stringWithFormat:#"%.10f",crnLoc.coordinate.latitude];
NSString *longitudeString = [NSString stringWithFormat:#"%.10f",crnLoc.coordinate.longitude];
NSString *urlString = [NSString stringWithFormat:#"https://api.foursquare.com/v2/venues/search?client_id=ACAO2JPKM1MXHQJCK45IIFKRFR2ZVL0QASMCBCG5NPJQWF2G&client_secret=YZCKUYJ1WHUV2QICBXUBEILZI1DMPUIDP5SHV043O04FKBHL&ll=%#,%#&query=coffee&v=20140806&m=foursquare", latitudeString, longitudeString];
NSURL *url = [NSURL URLWithString:urlString];
NSData *jsonData = [NSData dataWithContentsOfURL:url];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
NSDictionary *responseDictionary = [dataDictionary objectForKey:#"response"];
NSDictionary *venueDictionary = [responseDictionary objectForKey:#"venues"];
for (NSDictionary *dict in venueDictionary) {
NSString *name = [dict objectForKey:#"name"];
NSDictionary *locationDictionary = [dict objectForKey:#"location"];
NSString *address = [NSString stringWithFormat: #"%#", [locationDictionary objectForKey:#"address"]];
if (address == nil) {
address = #"No address provided";
}
NSString *distance = [NSString stringWithFormat: #"%#", [locationDictionary objectForKey:#"distance"]];
if (distance == nil) {
distance = #"No coordinates provided";
}
NSLog(#"Name: %# Address: %# distance: %#", name, address, distance);
CoffeeStore *store = [[CoffeeStore alloc] initWithName:name address:address distance:distance];
[resultArray addObject:store];
}
self.storeArray = resultArray;
[self.tableView reloadData]; }
and
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
CoffeeStore *selectedStore = self.storeArray[indexPath.row];
cell.textLabel.text = selectedStore.name;
cell.detailTextLabel.text = selectedStore.distanceString;
return cell;
}

Your resultArray contains an array of CoffeeStore objects, which have a distance given to their init method. You need to sort the array based on distance, before you call reloaddata. Hopefully those objects have a distance property and you can sort by that property, like this:
NSSortDescriptor *distanceDesc = [NSSortDescriptor sortDescriptorWithKey:#"distance" ascending:YES];
self.storeArray = [resultArray sortedArrayUsingDescriptors:#[distanceDesc]];

Related

Store the image into cache for avoiding frequent loading from url in tableview

NSURL *url =[NSURL URLWithString:
#"http://api.kivaws.org/v1/loans/search.json?status=fundraising"];
Serialisation part is done below
(void)connectionDidFinishLoading{
NSDictionary *allDict = [NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];
NSArray *loans = [allDict objectForKey:#"loans"];
countryArray = [[NSMutableArray alloc] init];
for (NSDictionary *diction in loans) {
Country *countryObj = [[Country alloc]init];
NSString *sector = [diction objectForKey:#"sector"];
countryObj.sector = sector;
NSDictionary *imageID = [diction objectForKey:#"image"];
NSString *img = [imageID objectForKey:#"id"];
countryObj.idValue=img;
NSString *activity = [diction objectForKey:#"activity"];
countryObj.activity = activity;
NSString *name = [diction objectForKey:#"name"];
countryObj.name = name;
NSDictionary *con = [diction objectForKey:#"location"];
NSString *world = [con objectForKey:#"country"];
countryObj.country= world;
NSString *towname = [con objectForKey:#"town"];
countryObj.down=towname;
[countryArray addObject:countryObj];
}
}
This contains both images and data. I need to store the image into cache.
Please use SDWebImage it contains everything you need. I am using this library for 2 years already.
Follow that tutorial which contains how to cache images inside a UIImageView with a simple one line of code and also a class that prefetches all the images in background, just create an NSArray with all the images you want to prefetch.
Hope that helps!

Using NSMutableArray in TableViewController with JSON data

Good afternoon,
I'm trying to use a NSMutableArray in my TableViewController from a JSON output and I'm a little bit lost because currently I can store my JSON data in a NSMutableArray, and I have checked with a NSLog that the content is OK, but now I have to show that data in my TableViewController and that's when I'm lost.
I'm using an another example of TableViewController using NSArray but now I have to modify it for a NSMutableArray. If you can help me with some code or show me some examples or tutorials I will be much appreciated.
I know in my code maybe I have something wrong because I'm using an old example using only NSArray but I'm showing you because that's what I don't know how to do, I need to work with NSMutableArray and that's why I'm asking for your help.
How can I show a NSMutableArray in my TableViewController?
- (void)viewDidLoad
{
[super viewDidLoad];
[self fetchJson];
}
-(void)fetchJson {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSString * urlString = [NSString stringWithFormat:#"http://website.com/service.php"];
NSURL * url = [NSURL URLWithString:urlString];
NSData * data = [NSData dataWithContentsOfURL:url];
//NSError * error;
//NSMutableArray *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
// I advice that you make your carModels mutable array and initialise it here,before start working with json
//self.carModels = [[NSMutableArray alloc] init];
NSMutableArray *carModels=[[NSMutableArray alloc]init];
NSMutableArray *carMakes=[[NSMutableArray alloc]init];
NSMutableArray *carImages=[[NSMutableArray alloc]init];
#try
{
NSError *error;
NSMutableArray* json = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
if (error)
{
NSLog(#"%#",[error localizedDescription]);
}
else
{
for(int i=0;i<json.count;i++)
{
NSDictionary * jsonObject = [json objectAtIndex:i];
NSString* imagen = [jsonObject objectForKey:#"imagen"];
[carImages addObject:imagen];
NSDictionary * jsonObject2 = [json objectAtIndex:i];
NSString* user = [jsonObject2 objectForKey:#"user"];
[carMakes addObject:user];
NSDictionary * jsonObject3 = [json objectAtIndex:i];
NSString* images = [jsonObject3 objectForKey:#"date"];
[carModels addObject:images];
}
}
}
#catch (NSException * e)
{
NSLog(#"Exception: %#", e);
}
#finally
{
NSLog(#"finally");
// That's showing the data "1, 2, 3".
NSLog(#"models: %#", carModels);
NSLog(#"makes: %#", carMakes);
NSLog(#"images: %#", carImages);
}
}
);
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.carModels count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"carTableCell";
CarTableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CarTableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.makeLabel.text = [_carMakes objectAtIndex: [indexPath row]];
cell.modelLabel.text = [self.carModels objectAtIndex:[indexPath row]];
UIImage *carPhoto = [UIImage imageNamed: [self.carImages objectAtIndex: [indexPath row]]];
cell.carImage.image = carPhoto;
return cell;
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowCarDetails"])
{
CarDetailViewController *detailViewController =
[segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView
indexPathForSelectedRow];
detailViewController.carDetailModel = [[NSArray alloc]
initWithObjects: [self.carMakes
objectAtIndex:[myIndexPath row]],
[self.carModels objectAtIndex:[myIndexPath row]],
[self.carImages objectAtIndex:[myIndexPath row]],
nil];
}
}
Thanks.
Declare NSMutableArray *jsonArray ; as global
-(void)fetchJson {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSString * urlString = [NSString stringWithFormat:#"http://website.com/service.php"];
NSURL * url = [NSURL URLWithString:urlString];
NSData * data = [NSData dataWithContentsOfURL:url];
//NSError * error;
//NSMutableArray *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
// I advice that you make your carModels mutable array and initialise it here,before start working with json
//self.carModels = [[NSMutableArray alloc] init];
#try
{
NSError *error;
[jsonArray removeAllObjects];
jsonArray = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
}
#catch (NSException * e)
{
NSLog(#"Exception: %#", e);
}
#finally
{
[self.tableView reloadData]
}
}
);
}
To Display The TableView Like This
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [jsonArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"carTableCell";
CarTableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CarTableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.makeLabel.text = [[jsonArray objectAtIndex:indexPath.row] valueForKey:#"imagen"];
cell.modelLabel.text = [[jsonArray objectAtIndex:indexPath.row] valueForKey:#"user"];
UIImage *carPhoto = [[jsonArray objectAtIndex:indexPath.row] valueForKey:#"date"];
cell.carImage.image = carPhoto;
return cell;
}
Add
[self.tableView reloadData]
after you have fetched and parsed the JSON.
Whenever you change table datas from different array just add [self.tableView reloadData] in you method.
It will remove old data & shows new data into your tableview.

NSInvalidArgumentException reason: data parameter is nil in UITableView while trying to display the Flickr images

Hi in my application I want to display the Flickr album list in UITableView so i have searched for long time and i have found some solution. I have used the method which given in the solution its not working its giving error like
NSInvalidArgumentException', reason: 'data parameter is nil
The solution link click here
And since I'm trying this for first time I'm not able resolve this issue. This is MY API LINK for Flickr
I have used this code to display the Flickr image Album list in UItableview
{
NSMutableArray *photoURLs;
NSMutableArray *photoSetNames;
NSMutableArray *photoid1;
}
My Flickr API key
#define FlickrAPIKey #"a6a0c7d5efccffc285b0fe5ee1d938e3"
- (void)viewDidLoad
{
[super viewDidLoad];
photoURLs = [[NSMutableArray alloc] init];
photoSetNames = [[NSMutableArray alloc] init];
photoid1 = [[NSMutableArray alloc] init];
[self loadFlickrPhotos];
}
My TableView code
- (void)loadFlickrPhotos
{
NSString *urlString = [NSString stringWithFormat:#"http://api.flickr.com/services/rest/?method=flickr.photosets.getList&api_key=%#&user_id=%#&per_page=10&format=json&nojsoncallback=1", FlickrAPIKey, #"124757153#N04"];
NSURL *url = [NSURL URLWithString:urlString];
NSString *jsonString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSDictionary *results = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
NSArray *photosets = [[results objectForKey:#"photosets"] objectForKey:#"photoset"];
for (NSDictionary *photoset in photosets) {
NSString *title = [[photoset objectForKey:#"title"] objectForKey:#"_content"];
[photoSetNames addObject:(title.length > 0 ? title : #"Untitled")];
NSString *photoid = [photoset objectForKey:#"id"];
[photoid1 addObject:photoid];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [photoSetNames count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier =#"Cell";
flickrpoliticalCell *cell =(flickrpoliticalCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[flickrpoliticalCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.tit.text = [photoSetNames objectAtIndex:indexPath.row];
return cell;
}
try this
- (void)loadFlickrPhotos
{
//
NSString *urlString = [NSString stringWithFormat:#"https://www.flickr.com/services/rest/?method=flickr.photosets.getList&api_key=a6a0c7d5efccffc285b0fe5ee1d938e3&format=json&user_id=124757153#N04&per_page=10&nojsoncallback=1",nil];
NSLog(#"the url string==%#",urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSString *jsonString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSLog(#"the str==%#",jsonString);
NSDictionary *results = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
NSArray *photosets = [[results objectForKey:#"photosets"] objectForKey:#"photoset"];
for (NSDictionary *photoset in photosets) {
NSString *title = [[photoset objectForKey:#"title"] objectForKey:#"_content"];
NSLog(#"title==%#",title);
[photoSetNames addObject:(title.length > 0 ? title : #"Untitled")];
NSString *primary = [photoset objectForKey:#"primary"];
NSString *server = [photoset objectForKey:#"server"];
NSString *secret = [photoset objectForKey:#"secret"];
NSString *farm = [photoset objectForKey:#"farm"];
NSString *urlstr=[NSString stringWithFormat:#"http://farm%#.staticflickr.com/%#/%#_%#.jpg",farm,server,primary,secret];
NSLog(#"your photo id==%#",urlstr);
[photoids addObject:urlstr];
}
}

Calling NSDictionary with NSArray KeyValue issue

I have an array that loaded with data from other method. The data type is like that in the debug for KEYS as in the code.
<__NSArrayI 0x9e82fc0>(
{
"choice_name" = "Data0";
},
{
"choice_name" = "Data1";
},
{
"choice_name" = "Data2";
},
Then I have called it twice in different method as I commented below and I get the value of the arrray: array0 or array1 nil. Where would be my problem?
- (void)requestPosistion:(ASIFormDataRequest *)request{
NSData *responseData = [request responseData];
NSString *jsonString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary *result = [jsonString JSONValue];
[jsonString release];
if (![SettingVO isValidResponce:result]) return;
CXMLDocument *doc = [[[CXMLDocument alloc] initWithXMLString:[result objectForKey:#"Response"] options:0 error:nil] autorelease];
NSArray *nodes = [doc nodesForXPath:#"/root" error:nil];
NSLog(#"choiceList is %#", nodes);
if([[[[nodes objectAtIndex:0] attributeForName:#"success"] stringValue] isEqualToString:#"true"])
{
NSArray *nodes3 = NULL;
nodes3 = [doc nodesForXPath:#"/root/cl_choicelist/cl_choice" error:nil];
NSLog(#"node3%#", nodes3);
res = [[NSMutableArray alloc] init];
for (CXMLElement *node in nodes3) {
item = [[NSMutableDictionary alloc] init];
int counter;
for(counter = 0; counter < [node childCount]; counter++) {
[item setObject:[[node childAtIndex:counter] stringValue] forKey:[[node childAtIndex:counter] name]];
}
[item setObject:[[node attributeForName:#"choice_name"] stringValue] forKey:#"choice_name"];
NSLog(#"item %#", item);
[res addObject:item];
[item release];
}
NSLog(#"res %#", res);
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *plistDict = [[NSDictionary alloc] initWithObjects:res forKeys:res];
//NSArray *keys = [plistDict allKeys];
//NSArray *array0 = [[NSArray alloc] initWithArray:[plistDict valueForKey:#"choice_name"]]; //array0 = nil.
NSArray *array1 = [plistDict objectForKey:#"choice_name"]; //array1 = nil.
Working code looks like that:
[[res objectAtIndex:0] objectForKey:#"choice_name"] //returns Data0
[[res objectAtIndex:1] objectForKey:#"choice_name"] //returns Data1
Most probably you want to use "indexPath" at objectAtIndex:
[[res objectAtIndex:[indexPath row]] objectForKey:#"choice_name"]
<__NSArrayI 0x9e82fc0>( { "choice_name" = "Data0"; }, { "choice_name" = "Data1"; }, { "choice_name" = "Data2"; },
This is an array. Inside the array you have object of NSDictionary with key "choice_name".
So in order to retrieve you need to iterate through the array to get all the kvp.
Replace your line with:
NSString *str = [plistDict valueForKey:#"choice_name"];
You have string for that key nor array.
Is always good to make sure your plistDict is not nil.
In NSDictionary you can have onelly one pair with key #choice_name. Even if you "put" more then one in NSDictionary, all other will just override previous value.
so valueForKey can return onelly one object and not the whole array, because there is onelly one key #choice_name.

JSON Geocoding for iOS - parse latitude/longitude to address

I am trying to create an autocomplete addresses suggestion using JSON.
The problem that I am facing is that I can get the latitude and longitude from a the user types on the UISearchDisplay. However I am trying to parse this data to addresses names. I was trying to use reverse geocoding from Apple but with no success. I am receiving only one value.
I was using apple geocoding straight away but the results were not what I was expecting.
Here is the code:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{
NSError *error;
NSString *lookUpString = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#&sensor=true", self.searchBar.text];
lookUpString = [lookUpString stringByReplacingOccurrencesOfString:#" " withString:#"+"];
NSData *jsonResponse = [NSData dataWithContentsOfURL:[NSURL URLWithString:lookUpString]];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonResponse options:kNilOptions error:&error];
self.locationArray = [[[jsonDict valueForKey:#"results"] valueForKey:#"geometry"] valueForKey:#"location"];
int total = self.locationArray.count;
for (int i = 0; i < total - 1; i++)
{
NSLog(#"locationArray count: %d", self.locationArray.count);
NSArray *localLocations;
localLocations = [self.locationArray objectAtIndex:i];
NSLog(#"%d",i);
NSString *latitudeString = [localLocations valueForKey:#"lat"];
NSString *longitudeString = [localLocations valueForKey:#"lng"];
NSLog(#"LatitudeString:%# & LongitudeString:%#", latitudeString, longitudeString);
NSString *statusString = [jsonDict valueForKey:#"status"];
NSLog(#"JSON Response Status:%#", statusString);
double latitude = 0.0;
double longitude = 0.0;
latitude = [latitudeString doubleValue];
longitude = [longitudeString doubleValue];
CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
[self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error){
[[self placemarks] addObject:placemarks];
NSLog(#"PLACEMARKS %d", self.placemarks.count);
}];
}
NSLog(#"Mutable array %d", self.placemarks.count);
[self.searchDisplayController.searchResultsTableView reloadData];
return NO;
}
The NSLog(#"PLACEMARKS %d", self.placemarks.count); only display once, in the end of the task.
Any suggestions?
I really was doing so much more than the necessary.
Here is my code now:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{
NSError *error;
NSString *lookUpString = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#&components=country:AU&sensor=false", self.searchBar.text];
lookUpString = [lookUpString stringByReplacingOccurrencesOfString:#" " withString:#"+"];
NSData *jsonResponse = [NSData dataWithContentsOfURL:[NSURL URLWithString:lookUpString]];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonResponse options:kNilOptions error:&error];
self.locationArray = [[jsonDict valueForKey:#"results"] valueForKey:#"geometry"];
int total = self.locationArray.count;
NSLog(#"locationArray count: %d", self.locationArray.count);
for (int i = 0; i < total; i++)
{
NSString *statusString = [jsonDict valueForKey:#"status"];
NSLog(#"JSON Response Status:%#", statusString);
NSLog(#"Address: %#", [self.locationArray objectAtIndex:i]);
}
[self.searchDisplayController.searchResultsTableView reloadData];
return NO;
}

Resources