I am getting data using json with this code and I need to display it in a tableview with two part code and name the problem is writing it all to an array is taking forever and the array comes back null. How can I get each returned element as its own tableview cell? Hundreds of airports are returned.
NSString* path = #"https://api.flightstats.com/flex/airports/rest/v1/json/active?appId=id&appKey=appkey";
NSMutableURLRequest* _request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:path]];
[_request setHTTPMethod:#"GET"];
NSURLResponse *response = nil;
NSError *error = nil;
NSData* _connectionData = [NSURLConnection sendSynchronousRequest:_request returningResponse:&response error:&error];
if(nil != error)
{
NSLog(#"Error: %#", error);
}
else
{
NSMutableDictionary* json = nil;
if(nil != _connectionData)
{
json = [NSJSONSerialization JSONObjectWithData:_connectionData options:NSJSONReadingMutableContainers error:&error];
}
if (error || !json)
{
NSLog(#"Could not parse loaded json with error:%#", error);
}
else
{
NSMutableDictionary *routeRes;
routeRes = [json objectForKey:#"airports"];
for(NSMutableDictionary *flight in routeRes)
{
NSLog(#"ident is %#", [flight objectForKey:#"name"]);
NSString *code=[json objectForKey:#"fs"];
NSString *name=[flight objectForKey:#"name"];
NSLog(#"code %#, name %#", code, name);
[candyArray addObject:[Candy code:code name:name]];
}
}
_connectionData = nil;
NSLog(#"connection done");
The following is the cellForRowatIndex were nothing is shown
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if ( cell == nil ) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Create a new Candy Object
Candy *candy = nil;
// Check to see whether the normal table or search results table is being displayed and set the Candy object from the appropriate array
if (tableView == self.searchDisplayController.searchResultsTableView)
{
candy = [filteredCandyArray objectAtIndex:[indexPath row]];
}
else
{
candy = [candyArray objectAtIndex:[indexPath row]];
}
// Configure the cell
[[cell textLabel] setText:[candy name]];
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
This is a sample of what the returned json is
{"airports":[{"fs":"CLO","iata":"CLO","icao":"SKCL","name":"Alfonso B. Aragon Airport","city":"Cali","cityCode":"CLO","countryCode":"CO","countryName":"Colombia","regionName":"South America","timeZoneRegionName":"America/Bogota","localTime":"2014-03-31T18:51:58.372","utcOffsetHours":-5.0,"latitude":3.543056,"longitude":-76.381389,"elevationFeet":3162,"classification":3,"active":true,"delayIndexUrl":"https://api.flightstats.com/flex/delayindex/rest/v1/json/airports/CLO?codeType=fs","weatherUrl":"https://api.flightstats.com/flex/weather/rest/v1/json/all/CLO?codeType=fs"}
This is the search function:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
// Update the filtered array based on the search text and scope.
// Remove all objects from the filtered search array
[self.filteredCandyArray removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.name contains[c] %#",searchText];
NSArray *tempArray = [airportsArray filteredArrayUsingPredicate:predicate];
NSLog(#" text %#", searchText);
filteredCandyArray = [NSMutableArray arrayWithArray:tempArray];
NSLog(#"NSLog %#", scope);
}
What's up with that candy object?
You have an array of dictionnary, here's how you parse that:
Get the array:
NSArray *airportsArray = [json objectForKey:#"airports"];
Set the cell text:
[[cell textLabel] setText:[[airportsArray objectAtIndex:indexPath.row]objectForKey:#"name"]];
[[cell detailTextLabel] setText:[[airportsArray objectAtIndex:indexPath.row]objectForKey:#"code"]];
or for better readability:
NSDictionary *airportAtIndex = [airportsArray objectAtIndex:indexPath.row];
[[cell textLabel] setText:[airportAtIndex objectForKey:#"name"]];
[[cell detailTextLabel] setText:[airportAtIndex objectForKey:#"code"]];
Can you elaborate on how I could use sendAsynch to speed up the process?
Ok, first thing to note, you are not speeding up anything here, the reason why you feel the UI is lagging is because you run the network request on the main thread.
You can solve that problem by sending the request asynchrously, meaning in a background thread which will not freeze your User Interface.
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//this is where you perform the network request
//You can fetch data, in your case get the JSON
dispatch_async(dispatch_get_main_queue(), ^(void){
//in this block you want to manipulate the the User Interface
//this is where you reload the tableView
//or stop an activity indicator
[self.tableView reloadData];
});
});
Things to note (from #HotLicks)
The app must be set up so that the TableView delegate will initially
(before the data is downloaded) report zero rows in the section. Then,
the reloadData op will cause the TableView to refresh the table. So
initially the table will be blank. One could fudge it slightly to
initially present a single cell saying "Data is loading" or anything that lets the user know >that an operation is in progress such as a UIActivityIndicator.
read up on Grand Central Dispatch (GCD)
You could take several approaches here in order to improve performance.
Start uploading and requesting airports as soon as possible in your application.
Complimentarily try to perform any heavy operation in a background thread, dispatching an asynchronous operation to build you array of Candy objects. You can use dispatch_async.
Another approach would be to have some kind of custom logic to avoid creating the whole array at a time… I would keep for example the JSON result (NSMutableDictionary *routeRes) and would create Candy objects on demand (every time a cell is required), keeping a trace of the last Candy index read / created in the JSON up to finish parsing all the dictionary (then you can start reading your array of candies)…. That could work if Candy creation logic is not too heavy (I think it's not).
Related
I want to fetch data from server with multiple calls inside for loop. I'm passing different parameter each time. I know it is possible to fetch data like, I'm fetching in code below :
for (NSDictionary *feedItem in [feed objectForKey:#"content"]) {
// url with feedItem data.
NSURL *url = ....
[UrlMethod GetURL:url success:^(NSDictionary *placeData) {
if (placeData) {
dispatch_async(dispatch_get_main_queue(), ^{
// adding object to table data source array
[dataSourceArray addObject:[placeData objectForKey:#"data"]];
// reloading table view.
[self.tableView reloadData];
});
}
} failure:^(NSError *error) {
}];
}
The problem is, Whenever I add data to dataSourceArry, It is not adding sequentially. It is adding according to response of API calls. Please let me know, If it is not clear.
In your case, I would allocate a mutable array first and set [NSNull null] at each position:
NSInteger count = [[feed objectForKey:#"content"] count];
NSMutableArray *dataSourceArray = [NSMutableArray arrayWithCapacity:count];
for (NSInteger i = 0; i < count; ++i) {
[dataSourceArray addObject:[NSNull null]];
}
Then, I would use something called dispatch groups (see more here http://commandshift.co.uk/blog/2014/03/19/using-dispatch-groups-to-wait-for-multiple-web-services/):
__block NSError *apiCallError = nil; // Just to keep track if there was at least one API call error
NSInteger index = 0;
// Create the dispatch group
dispatch_group_t serviceGroup = dispatch_group_create();
for (NSDictionary *feedItem in [feed objectForKey:#"content"]) {
// Start a new service call
dispatch_group_enter(serviceGroup);
// url with feedItem data.
NSURL *url = ...
[UrlMethod GetURL:url success:^(NSDictionary *placeData) {
if (placeData) {
dispatch_async(dispatch_get_main_queue(), ^{
// Add data to Data Source
// index should be the correct one, as the completion block will contain a snapshot of the corresponding value of index
dataSourceArray[index] = [placeData objectForKey:#"data"];
}
dispatch_group_leave(serviceGroup);
} failure:^(NSError *error) {
apiCallError = error;
dispatch_group_leave(serviceGroup);
}];
index++;
}
dispatch_group_notify(serviceGroup, dispatch_get_main_queue(),^{
if (apiCallError) {
// Make sure the Data Source contains no [NSNull null] anymore
[dataSourceArray removeObjectIdenticalTo:[NSNull null]];
}
// Reload Table View
[self.tableView reloadData];
});
Hope it works for you.
This might be of help for you,
//keep dictionary property which will store responses
NSMutableDictionary *storeResponses = [[NSMutableDictionary alloc]init];
//Somewhere outside function keep count or for loop
NSInteger count = 0;
for (NSDictionary *feedItem in [feed objectForKey:#"content"]) {
//Find out index of feddItem
NSInteger indexOfFeedItem = [[feed objectForKey:#"content"] indexOfObject:feedItem];
NSString *keyToStoreResponse = [NSString stringWithFormat:#"%d",indexOfFeedItem];
// url with feedItem data.
NSURL *url = ....
[UrlMethod GetURL:url success:^(NSDictionary *placeData) {
if (placeData) {
//instead of storing directly to array like below
// adding object to table data source array
[dataSourceArray addObject:[placeData objectForKey:#"data"]];
//follow this
//increase count
count++;
[storeResponses setObject:[placeData objectForKey:#"data"] forKey:keyToStoreResponse];
// reloading table view.
if(count == [feed objectForKey:#"content"].count)
{
NSMutableArray *keys = [[storeResponses allKeys] mutableCopy]; //or AllKeys
//sort this array using sort descriptor
//after sorting "keys"
for (NSString *key in keys)
{
//add them serially
[dataSourceArray addObject:[storeResponses objectForKey:key]];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
}
} failure:^(NSError *error) {
}];
}
Edit : The answer I have given is directly written here,you might face compilation errors while actually running this code
Don't reload your table each time in the loop. After the loop finishes fetching data , do a sorting on your datasourcearray to get the desired result and then reload table.
This is because you're calling web-services asynchronously so it's not give guarantee that it's give response in sequence as you have made request!
Now solutions for that :
You should write your api like it's give all data at a time. So,
You not need to make many network call and it will improve
performance also!
Second thing you can make recursive kind of function, I mean make another request from completion handler of previous one. In this case once you got response then only another request will be initialize but in this case you will have to compromise with performance!! So first solution is better according to me!
Another thing you can sort your array after you get all the responses and then you can reload your tableView
Try the following :-
for (NSDictionary *feedItem in [feed objectForKey:#"content"]) {
// url with feedItem data.
NSURL *url = ....
[UrlMethod GetURL:url success:^(NSDictionary *placeData) {
if (placeData) {
// adding object to table data source array
[dataSourceArray addObject:[placeData objectForKey:#"data"]];
// reloading table view.
dispatch_sync(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
} failure:^(NSError *error) {
}];
}
My task is simple basically for most of you, but obviously im doing something wrong here.
I have a two table view controllers that I want to populate their cells based on some object status. Im working with core data so also doing fetchResultController too.
in one of the view controllers I can change the status of the cell object (not the actual cell, the object that is populating the cell), and whenever that happened I want to delete this cell from the table view. In that view controller I want to present only the cells that the object that is populating them have the status = 0. but I dont want to delete the ones that was deleted, just to change their status to 1, and then in some other view controller to present them if they have the status = 1.
So what im doing is:
Whenever the commitEditingStyle is getting called:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
target.status = #1;
}
if ([_delegate respondsToSelector:#selector(didDeleteObject)]) {
[self fetchData];
[_delegate didDeleteObject];
}
}
Now what I had in mind is in the cellForRowAtIndexPath method to add a condition when im returning a cell like this:
if ([target.status isEqual:#0]) {
return cell;
}
return NULL;
}
since I want to present only the cells that have the status 0...
So now obviously I cannot enter this table view because I have to return a cell in this method and not done, how can i just say that if the statues of the object target is different than 1 so dont present the cell?
other code solutions will be great too :)
thanks!!!
You should be able to filter out fetch request with a predicate
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Target"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"status == %#", [NSNumber numberWithBool:NO]];
[fetchRequest setPredicate:predicate];
When you set your status attribute to 1, FetchedResultsController will automatically delete cell from the tableView, but the object will not get deleted. You don't have to do anything in the cellForRowAtIndexPath. And in your other tableView, set the predicate to only fetch status == 1.
Also, make sure to save the managedObjectContext when you change the attribute's value.
Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
target.status = #1;
NSError *error = nil;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Save Failed! %# %#", error, [error localizedDescription]);
}
You can't do it in this way.
You have to set a dynamic numberOfRowsInSection:, depending on how many Target has status property equal to #0
So, in tableView:cellForRowAtIndexPath: you will return the cell only if the status is #0.
For me is better if you split the dataSource in dataSource with target.status = #0 and others.
A right way is this
// This is the point where you have an update dataSource array (not splitted)
updatedDatas = [Manager getLatestData];
if (dataSource.count > 0)
[dataSource removeAllObjects];
[updatedDatas enumerateObjectsUsingBlock:^(Target *obj, NSUInteger idx, BOOL *stop) {
if ([obj.status integerValue] == 0)
[dataSource addObject: obj];
}];
updatedDatas = nil;
// This is the numberOfRowsInSection:
- (NSInterger)numberOfRowsInSection:(NSInteger)section{
return dataSource.count;
}
In the tableView:cellForRowAtIndexPath: you will now use the dataSource NSMutableArray with a simple objectAtIndex: to access the correct element
I'm trying to fetch a Core Data object and load it from a UITableView that is NOT made up from Core Data objects. It's simply a UITableView made with a predetermined array, but I want to load an object in Core Data with the same name as the cells detailTextLabel. I tried following this tutorial to load a specific value, but it's not working: It crashes or tells me my entity is nil, which it's not.
So basically I have a UITableView and it loads with this array:
array = #[#"publication 1",#"publication 2", etc]
Then, when a user selects the cell, I would like it to load a document based on the cells detailText, but it always loads whatever the objects indexPath is, instead of based on the cells detailText. So say in the main view controller where the predetermined array is loaded into the table view, I tap on Memo 24, but its index is (0,2) it will load an object, but it will load the object in the downloads entity that has the same indexPath (whatever publication is at 0,2) number as opposed to the Memo 24 title.
Here is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[self loadPublicationLocallyWithPubAtIndex:indexPath withTitle:cell.detailTextLabel.text];
}
- (void)loadPublicationLocallyWithPubAtIndex:(NSIndexPath *)indexPath withTitle:(NSString *)pubNumber {
NSManagedObjectContext *selectedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *phrase = nil; // Document password (for unlocking most encrypted PDF files)
NSString *filePath;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"PDFs"];
filePath = [filePath stringByAppendingPathComponent:[selectedObject valueForKey:#"puburl"]]; assert(filePath != nil); ;
NSLog(#"Local path is : %#", filePath);
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
//File exists
NSData *data = [[NSData alloc] initWithContentsOfFile:filePath];
if (data)
{
//load document
}
}
}
It works for all my view controllers that populate with Core Data, no matter what indexPath the cell is, it still retrieves the right object, so that leads me to believe it has something to do with the [self.fetchedResultsController objectAtIndex:]; part, so I even tried:
NSIndexPath *selectedItem = [self.fetchedResultsController indexPathForObject:cell.detailTextLabel.text];
in didSelectRowAtIndexPath:, but it doesn't work either.
How do you load an object based on a cells detailTextLabel as opposed to its indexPath?
If you are populating your array from a static array, then you probably don't need to use a fetched results controller. You should instead just execute a fetch to get the relevant NSManagedObject. To ensure the fetch gets only the relevant object, use a predicate.
Suppose your NSManagedObjects are in a Publication Entity, and the relevant attribute is title. You should build a fetch like this:
NSManagedObjectContext *context = self.managedObjectContext; // or however your context is obtained
NSManagedObject *selectedObject;
NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:#"Publication"]; // amend entity name as appropriate
fetch.predicate = [NSPredicate predicateWithFormat:#"title == %#",pubNumber];
NSError *error;
NSArray *results = [context executeFetchRequest:fetch error:&error];
if (results == nil) {
NSLog(#"Fetch error %#, %#", error, [error userInfo]);
abort();
} else {
if ([results count] == 0) {
NSLog(#"Publication not found");
} else {
// (note, should probably also check for count > 1 and handle accordingly)
selectedObject = results[0];
// then carry on with the remaining code from loadPublicationLocally....
NSString *phrase = nil; // Document password (for unlocking most encrypted PDF files)
NSString *filePath;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"PDFs"];
filePath = [filePath stringByAppendingPathComponent:[selectedObject valueForKey:#"puburl"]]; assert(filePath != nil); ;
// ... etc etc.
}
}
I am getting the response from JSON and stored that data by using Core Data. I want to show the data always in a UITableView. Can you suggest me how to display data in a UITableView?
This is the code I'm using.
NSManagedObject * newEntry =[[NSManagedObject alloc]initWithEntity:entityDesc insertIntoManagedObjectContext:self.managedObjectContext];
[newEntry setValue:[dict objectForKey:#"albumName"] forKey:#"albumName"];
[newEntry setValue:[dict objectForKey:#"coverPhotoURL"] forKey:#"coverPhotoURL"];
[newEntry setValue:[dict objectForKey:#"createdDate"] forKey:#"createdDate"];
NSLog(#"Log %#", newEntry);
NSError * error = nil;
if ([self.managedObjectContext save:&error] == NO)
{
NSLog(#"CANNOT SAVE: %# %#", error, [error localizedDescription]);
}
else {
NSLog(#"SUCCES, go check the sqlite file");
}
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"GetAlbums"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError* error;
NSArray *fetchedRecords = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(#"Fetch Records %#",fetchedRecords);
Even if, as suggested by walle84, you can implement the methods of UITableViewDelegate to display data in your table view, the right way is to use a UITableView in combination with NSFetchedResultsController. The latter is, as written in the doc, used
to efficiently manage the results returned from a Core Data fetch request to provide data for a UITableView object.
I put the emphasis on efficiently since it provides a lot of pros. For example, it allows lazy loading of data, it allows to track changes for a specific entity (implementing NSFetchedResultsControllerDelegate), etc.
Where to start? There are a lot of tuts. Just google them and you will find a good point to start.
Core Data From Scratch
How To Use NSFetchedResultsController
You use below methods of table view so show your data.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.arrayOfyourData count];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CellIdentifier";
//you could use default cell or ur own custom cell.
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// Now here you could pare your self.arrayOfyourData to fetch and populate your cell.
return cell;
}
New to iOS. I am downloading JSON data using AFNetworking and putting the data in a Dictionary object. This is done in the following code:
-(void)locationRequest
{
NSURL *url = [NSURL URLWithString:#"http://sitespec/php/getlocations.php"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//AFNetworking asynchronous url request
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id responseObject)
{
self.locationsFromJSON = (NSDictionary *)responseObject;
NSLog(#"JSON RESULT %#", responseObject);
NSLog(#"JSON DICTIONARY %#", _locationsFromJSON);
[self.tableView reloadData];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id responseObject)
{
NSLog(#"Request Failed: %#, %#", error, error.userInfo);
}];
[operation start];
}
I am getting the data and populating the Dictionary array as seen in the outpur of the NSLOG calls below:
2013-05-12 12:44:08.851 sitespec[2024:c07] JSON RESULT (
{
city = "Rocky Mount";
id = 1;
name = "Rocky Mount";
phone = "(252) 451-1811";
state = NC;
"street_address" = "620 Health Drive";
zip = 27804;
},
{
city = "Elizabeth City";
id = 2;
name = "Elizabeth City";
phone = "(252) 335-4355";
state = NC;
"street_address" = "109 Corporate Drive";
zip = 27906;
}
)
2013-05-12 12:44:08.852 sitespec[2024:c07] JSON DICTIONARY (
{
city = "Rocky Mount";
id = 1;
name = "Rocky Mount";
phone = "(252) 451-1811";
state = NC;
"street_address" = "620 Health Drive";
zip = 27804;
},
{
city = "Elizabeth City";
id = 2;
name = "Elizabeth City";
phone = "(252) 335-4355";
state = NC;
"street_address" = "109 Corporate Drive";
zip = 27906;
}
)
BUT, here is where I am lost.....
How do I access this data in the Dictionary object in my
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method?
SOmething like:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [self.locationsFromJSON objectForKey:#"name"];
???
This is not working and I get a SIGBART error. I just cant figure out how to read the data out and populate the table view?
How do I do this? ANy help is GREATLY appreciated.....
I see this very often and I don't understand why people struggle to extract data from a dictionary and populate a table view with the content of a dictionary. I don't understand why people don't create model classes for the JSON response and after that add the models into an array depending on what they need.
So Tommy I strongly recommend that you create a class model named Address (for example) and add all the JSON attributes as properties to your model class, when you parse your JSON you create Address class instances that you will add to an array. After that, in your table view class you will have an array of addresses and for:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section you will return yourAddressesArray.count
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { Address *address = [yourAddressesArray objectAtIndex:indexPath.row]; //assign your address properties to labels etc
}
It's easier when you have model classes ;)
EDIT FOR PARSING
From what I see in your question you have an array of dictionaries. So I suggest to do something like this:
In your Address class create an imit method with josn:
-(id)initAddressWithJSON:(id)JSON {
slef = [super init];
if(self) {
self.city = [JSON objectForKey:#"city"];
// set all the properties here
}
return self;
}
When you received the json response called, let's say "jsonResopnse" you should do something like:
-(NSArray*)myAddressesFromJSON:(id)JSON {
//you should add a validation here for JSON (not null not empty)
NSMutableArray *addresses = [[NSMutableArray alloc] init];
Address *address;
for(NSDictionary *addressDict in JSON) {
address = [[Address alloc] initWithJSON:addressDict];
[addresses addObject:address];
}
return addresses;
}
Note, I wrote the code from my head and I didn't used Xcode :) and is possible that there are some build errors (misspelling), but I hope you got the idea. Also I suppose you are using JSONKit.
As I see, you use the JSON request and the UITableView in same class. Set a breakpoint in the cellForRowAtIndexPath methode and check what if there are already Data. if no, then:
ask in the - (NSInteger)numberOfRowsInSection:(NSInteger)section methode or already in numberOfSections if your dictionary is already filled. else return 0.
And in the methode where you receive the JSON data call a [tableView reloadData];
if that is not the problem, please tell where you get the SIGBART error ;)
Thanks to danypata for the great feedback. I took a slightly different route to get this going. What got me thinking was danypata's comment "looks like you have a array of dictionaires in your JSON response".... In the AFNetworking block were I get the JSON response, I assign the JSON object to an array defined as a property in the current TableVIewCOntroller.
-(void)locationRequest
{
NSURL *url = [NSURL URLWithString:#"myurl"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//AFNetworking asynchronous url request
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id responseObject)
{
self.locationsFromJSON = responseObject;
[self.tableView reloadData];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id responseObject)
{
NSLog(#"Request Failed: %#, %#", error, error.userInfo);
}];
[operation start];
}
I also declare a Mutable Dictionary property and a NSString property for each value in my JSON response. In the TableVIewCell method below, I grab the dictionary objected located at index.row and read out the values for the keys and assign them to the prototype cell label properties.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"locCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
self.dictObj = [[NSMutableDictionary alloc] init];
self.dictObj = [_locationsFromJSON objectAtIndex:indexPath.row];
cell.textLabel.text = [_dictObj valueForKey:#"city"];
cell.detailTextLabel.text = [_dictObj valueForKey:#"phone"];
return cell;
}
THis worked! It just took someone else pointing out the obvious "looks like you have an Array of Dictionary objects....."