retaining data outside of viewDidLoad in objective c ios - ios

I am aware this question has been asked previously, but the answers provided have not solved my issue.
For instance, I have a very simple array of objects outlined in viewDidLoad:
#implementation MyViewController {
NSArray *tableData;
}
- (void)viewDidLoad
{
[super viewDidLoad];
tableData = [NSArray arrayWithObjects:#"Hello", #"My", #"Name", #"Is"];
NSLog(#"My Data: %#", tableData);
which is called in a tableView using cellForRowAtIndexPath
cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
This works fine and the NSLog shows my array. However, when i outline tableData outside of viewDidLoad, my array is (null).
My question is, how do I make my array available for the tableView when it is specified outside of ViewDidLoad?
edit: Here is my specific code:
#import <UIKit/UIKit.h>
#import "PhotoView.h"
#interface FrontViewController : UIViewController
#property (nonatomic, retain) UITableView *tableView;
#end
#import "FrontViewController.h"
#import "StreamScreen.h"
#import "API.h"
#import "PhotoView.h"
#import "StreamPhotoScreen.h"
#import "PrivateViewController.h"
#import "SWRevealViewController.h"
#import "PhotoScreen.h"
#import "RearViewController.h"
#import "SimpleTableCell.h"
#interface FrontViewController()
// Private Methods:
- (IBAction)pushExample:(id)sender;
#end
#implementation FrontViewController{
NSArray *tableData;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = NSLocalizedString(#"Front View", nil);
SWRevealViewController *revealController = [self revealViewController];
[self.navigationController.navigationBar addGestureRecognizer:revealController.panGestureRecognizer];
UIBarButtonItem *revealButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"reveal-icon.png"]
style:UIBarButtonItemStyleBordered target:revealController action:#selector(revealToggle:)];
self.navigationItem.leftBarButtonItem = revealButtonItem;
// This works if I uncomment
//tableData = [NSArray arrayWithObjects:#"Hello", #"My", #"Name", #"Is", nil];
[self refreshStream];
}
-(void)refreshStream {
// call the "stream" command from the web API
[[API sharedInstance] commandWithParams:
[NSMutableDictionary dictionaryWithObjectsAndKeys:#"stream", #"command", nil]
onCompletion:^(NSDictionary *json) {
//got stream
[self showStream:[json objectForKey:#"result"]];
NSMutableArray *myData = [[NSMutableArray alloc] init];
myData = [json objectForKey:#"result"];
NSArray *userNameData = [myData valueForKey:#"username"];
[self loadData];
tableData = userNameData;
[self.tableView reloadData];
// I can see my json array in NSLog
NSLog(#"here's the results: %#", tableData);
}];
}
//This doesn't work either
//-(void)loadData {
// Add the data to your array.
//tableData = [NSArray arrayWithObjects:#"Hello", #"My", #"Name", #"Is", nil];
//NSLog(#"My Data: %#", tableData);
// Now load the table view.
// [self.tableView reloadData];
//}
-(void)showStream:(NSArray*)stream {
for (int i=0;i<[stream count];i++) {
NSDictionary* photo = [stream objectAtIndex:i];
}
NSArray *checkData = [stream valueForKey:#"username"];
//I can see my data in NSLog
NSLog(#"here's the results: %#", checkData);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableData count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 78;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
cell.thumbnailImageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
cell.prepTimeLabel.text = [prepTime objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"didSelectRowAtIndexPath");
/*UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:#"You've selected a row" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];*/
UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:[tableData objectAtIndex:indexPath.row] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
// Display the Hello World Message
[messageAlert show];
// Checked the selected row
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"willSelectRowAtIndexPath");
if (indexPath.row == 0) {
return nil;
}
return indexPath;
}
#end

-(void)refreshStream {
// call the "stream" command from the web API
[[API sharedInstance] commandWithParams:
[NSMutableDictionary dictionaryWithObjectsAndKeys:#"stream", #"command", nil]
onCompletion:^(NSDictionary *json) {
//got stream
[self showStream:[json objectForKey:#"result"]];
NSMutableArray *myData = [json objectForKey:#"result"];
NSArray *userNameData = [myData valueForKey:#"username"];
}];
tableData = userNameData;
[self.tableView reloadData];
}
You're falling into a very common trap with asynchronous programming here.
commandWithParams takes a completion block, which is where you are getting the data out of the JSON. This block is not executed until the API call has returned. The sequence of events that happens when you run this code is:
commandWithParams is called
tableData is assigned to the contents of userNameData (which presumably you've also declared somewhere else otherwise this would not even compile)
reloadData is called
.... time passes
The completion block is executed and the JSON is read out into local variables, which are then instantly destroyed.
You need to move the two lines (points 2 and 3 in the list above) inside the completion block. There will be no data for your table until the block returns.

Ok my understanding of your question is that you want to assign variables to your NSArray in another method (not viewDidLoad) and then load the table view.
This is simple, just make a method which is in charge of adding the data to your array and then reload your table view like so:
-(void)viewDidLoad {
[super viewDidLoad];
// Call your method.
[self loadData];
}
-(void)loadData {
// Add the data to your array.
tableData = [NSArray arrayWithObjects:#"Hello", #"My", #"Name", #"Is"];
NSLog(#"My Data: %#", tableData);
// Now load the table view.
[myTableView reloadData];
}
Update 1
It would be much more helpful if you could share your code with us. How your and setting up your tableview, when its being called/etc....
Update 2
Ok well it seems obvious what yoru issue is. Your table view will never load like that. You need to call the tableview reloadData method outside the cellForRowAtIndexPath method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[self.tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
cell.thumbnailImageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
cell.prepTimeLabel.text = [prepTime objectAtIndex:indexPath.row];
return cell;
}
So the method call [self.tableView reloadData]; should only be called in your refreshStream method.
Update 3
You need to initialize your NSMutableArray before you can add data to it. initialize it in your refreshStrem method like so:
-(void)refreshStream {
// call the "stream" command from the web API
[[API sharedInstance] commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys:#"stream", #"command", nil] onCompletion:^(NSDictionary *json) {
//got stream
[self showStream:[json objectForKey:#"result"]];
NSMutableArray *myData = [[NSMutableArray alloc] init];
myData = [json objectForKey:#"result"];
NSArray *userNameData = [myData valueForKey:#"username"];
}];
tableData = userNameData;
[self.tableView reloadData];
}
Update 4
Ok well after reading #jrturton answer, I think its safe to assume that my answer is rubbish. To anyone reading my answer, please view #jrturton post.

Well I feel pretty sheepish. The answer was simple. I was so hung up on Json and API that all I didn't check the basics. All I need was in my .h file:
#property (strong, nonatomic) IBOutlet UITableView *tableView;
I had originally had:
#property (nonatomic, retain) UITableView *tableView;

Related

How to send value to anthor Page from table view iOS [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 8 years ago.
I have done for parsing data from JSON and put it show in Table view.
So I want to pass data (catID and catName )to another Page it's DetailPageController
how can I do like that? the below is my code.
Thanks in advance!
#import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *myObject;
// A dictionary object
NSDictionary *dictionary;
// Define keys
NSString *catName;
NSString *catID;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
catName =#"Category Name";
catID=#"Category ID";
myObject = [[NSMutableArray alloc] init];
NSData *jsonSource = [NSData dataWithContentsOfURL:
[NSURL URLWithString:#"MY_URL"]];
id jsonObjects = [NSJSONSerialization JSONObjectWithData:
jsonSource options:NSJSONReadingMutableContainers error:nil];
for (NSDictionary *dataDict in jsonObjects) {
NSString *TheCatName = [dataDict objectForKey:#"cat_name"];
NSString *TheCatID = [dataDict objectForKey:#"cat_id"];
NSLog(#"cat_name: %#",TheCatName);
NSLog(#"cat_id: %#",TheCatID);
dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
TheCatName, catName,
TheCatID, catID,
nil];
[myObject addObject:dictionary];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return myObject.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Item";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell=[[UITableViewCell alloc]initWithStyle:
UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSDictionary *tmpDict = [myObject objectAtIndex:indexPath.row];
NSMutableString *textcat;
textcat = [NSMutableString stringWithFormat:#"%#",
[tmpDict objectForKeyedSubscript:catName]];
NSMutableString *catid;
catid = [NSMutableString stringWithFormat:#"ID: %# ",
[tmpDict objectForKey:catID]];
cell.textLabel.text = textcat;
cell.detailTextLabel.text= catid;
return cell;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *tmpDict = [myObject objectAtIndex:indexPath.row];
NSMutableString *catID;
catID = [NSMutableString stringWithFormat:#"%#",
[tmpDict objectForKeyedSubscript:cat_id]];
NSLog(#"didSelectRowAtIndexPath");
/*UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:#"You've selected a row" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];*/
UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:catID delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
// Display the Hello World Message
[messageAlert show];
// Checked the selected row
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
First import DetailPageController in TableviewController Class with help of following line.
#import "DetailPageController.h"
Now implement following method in your TableViewController Class
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailPageController * detailPageControllerOBJ_ = [[ImageOptionViewController alloc]initWithNibName:#“XIBName bundle:nil];
detailPageControllerOBJ_.dicSelectedData = [self.arrayData objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detailPageControllerOBJ_ animated:YES];
}
And in DetailPageController.h put following code.
#property (nonatomic,strong) NSDictionary * dicSelectedData;
You will get your selected data in dicSelectedData Dictionary

How can I display multiple parameters of the same key from a .plist File on Objective-c?

I have this arquivo.plist below.
I looked at Apple's documentation, but I could not find how to make the listing look and I hope someone can help me.
In the first UITableView, I make a list of names present in arquivo.plist using the following code and loading the following method below.
What I'm trying to do is: When the user clicks on a tableView name, he is taken to a second screen with a new tableView that will display the "frams" of that user.
The problem is that the code I'm using to select the "frams" is the same code that I am using for listing the names on the first screen, but it is not working, because each user has only one name, but it has several "frams".
When I try to implement this, I can even assemble the array with the "frams" and pass using segue (i'll show the array with an NSLog), but this array can not be displayed as a tableView for an error that Xcode is giving me:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary length]:
unrecognized selector sent to instance 0x8b87a60'
The code from the fist view (ViewController.m) is below the contatos.plist
I hope you understand what I'm trying to do and bring me a light!
Thank you all!
a screenshot of the .plist file is bellow:
http://img268.imageshack.us/img268/7356/jl26.png
For reference and for you to better understand the issue, when the user clicks on a table name, an array is generated with "frams" this patient (patients have on average 3 frams each). The Array NSLog that it should be passed to the other page and comport a new table generates the following text:
12/12/2013 16:10:13.513 rer [24251:70 b] (
{
1 = 11;
2 = 12;
3 = 13;
}
I think that's where the problem lies, because this method of Array can not be implemented in a TableView, so I look a light of a better way to mount this array and select frams when I click a patient
So here is my ViewController.m:
#import "ViewController.h"
#import "Contato.h"
#import "perfilViewController.h"
#interface ViewController ()
-(void) loadContacts;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self loadContacts];
}
-(void) loadContacts
{
NSString *plistCaminho = [[NSBundle mainBundle] pathForResource:#"contatos"
ofType:#"plist"];
NSDictionary *pl = [NSDictionary dictionaryWithContentsOfFile:plistCaminho];
NSArray *dados = [pl valueForKey:#"contatos"];
contatos = [[NSMutableArray alloc] init];
for (NSDictionary *item in dados) {
NSString *nome = [item valueForKey:#"nome"];
NSString *telefone = [item valueForKey:#"telefone"];
NSString *fram = [item valueForKey:#"fram"];
Contato *c = [[Contato alloc] initWithNome:nome andTelefone:telefone andFram:fram];
[contatos addObject:c];
}
}
#pragma mark UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return contatos.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CelulaContatoCacheID = #"CelulaContatoCacheID";
UITableViewCell *cell = [self.tabelaContatos dequeueReusableCellWithIdentifier:CelulaContatoCacheID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CelulaContatoCacheID];
}
Contato *contato = [contatos objectAtIndex:indexPath.row];
cell.textLabel.text = contato.nome;
return cell;
}
#pragma mark -
#pragma mark UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Contato *contato = [contatos objectAtIndex:indexPath.row];
NSString *msg = [NSString stringWithFormat:#"Fram:%#",contato.fram];
fran = [[NSMutableArray alloc] init];
fran = [NSMutableArray arrayWithObject:contato.telefone];
NSLog(#"finalmente eu consegui essa porra!!!%#", fran);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Contato"
message:msg
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[self.tabelaContatos deselectRowAtIndexPath:indexPath animated:YES];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"vai"]) {
NSIndexPath *indexPath = [self.tabelaContatos indexPathForSelectedRow];
perfilViewController *destViewController = segue.destinationViewController;
Contato *contato = [contatos objectAtIndex:indexPath.row];
fran = [[NSMutableArray alloc] init];
fran = [NSMutableArray arrayWithObject:contato.fram];
destViewController.frans = fran;
NSLog(#"%#%#", fran, destViewController.frans);
}
}
#end
I'd firstly do:
//declare NSDictionary *pl; in the ViewController.h
pl = [NSDictionary dictionaryWithContentsOfFile:plistCaminho];
Then to display Names, i'd simply use the dictionary as such:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[pl objectForKey:#"contatos"] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...
//following commented line not needed anymore
//Contato *contato = [contatos objectAtIndex:indexPath.row];
cell.textLabel.text = [[[pl objectForKey:#"contatos"]
objectAtIndex:indexPath.row]
objectForKey:#"nome"];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//following commented line not needed anymore
//Contato *contato = [contatos objectAtIndex:indexPath.row];
//NOTE: fran is a dictionary now
//change "fran" declaration in the ViewController.h to
//NSDictionary *fran;
fran = [[NSDictionary alloc] init];
fran = [[pl objectForKey:#"contatos"]
objectAtIndex:indexPath.row];
NSLog(#"finalmente eu consegui essa porra!!!%#", fran);
//...
//don't deselectRow (the indexPathForSelectedRow will not work correctly later)
//[self.tabelaContatos deselectRowAtIndexPath:indexPath animated:YES];
}
then on -prepareForSegue i'd pass the dictionary associated with the selected row:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"vai"]) {
NSIndexPath *indexPath = [self.tabelaContatos indexPathForSelectedRow];
perfilViewController *destViewController = segue.destinationViewController;
//following commented line not needed anymore
//Contato *contato = [contatos objectAtIndex:indexPath.row];
//NOTE: fran is a dictionary now
//change "fran" declaration in the ViewController.h to
//NSDictionary *fran;
fran = [[NSDictionary alloc] init];
fran = [[[pl objectForKey:#"contatos"]
objectAtIndex:indexPath.row]
objectForKey:#"fram"];
//NOTE: destViewController.frans should be a dictionary
//handle it appropriately
destViewController.frans = fran;
}
}
so basically, all dictionary use, no need for Contato *contato at all.
EDIT: As for your current method, you would be better off replicating the same structure.
As in:
[array of names] has {dictionary with user details} having a key that has {dictionary of frams}
I'd recommend you not using a dictionary to store your Fram values, use an array instead.
This way, you can get the Fram values like this:
for (NSDictionary *item in dados) {
NSString *nome = [item valueForKey:#"nome"];
NSString *telefone = [item valueForKey:#"telefone"];
NSArray *fram = [item valueForKey:#"fram"];
Contato *c = [[Contato alloc] initWithNome:nome andTelefone:telefone andFram:[fram objectAtIndex:index]];
[contatos addObject:c];
}
Where index is an integer variable you'll have to work out how to handle.
PS: be a little more polite when logging you app ;)

Parsing JSON image urls in iOS error

I'm trying to parse a JSON file containing some links to images and some titles and times.
This is my code:
#import "PicturesViewController.h"
#import "DemoViewController.h"
#import "SecondViewController.h"
#import "AppDelegate.h"
#import "RNBlurModalView.h"
#import "PictureJSON.h"
#import "HMSegmentedControl.h"
#interface PicturesViewController ()
{
NSInteger refreshIndex;
NSArray *images;
}
#end
#implementation PicturesViewController
- (void)viewDidLoad
{
HMSegmentedControl *segmentedControl = [[HMSegmentedControl alloc] initWithSectionTitles:#[#"Instagram", #"Hashtags", #"Facebook"]];
[segmentedControl setFrame:CGRectMake(10, 10, 300, 60)];
[segmentedControl addTarget:self action:#selector(segmentedControlChangedValue:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:segmentedControl];
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Menu" style:UIBarButtonItemStyleBordered target:self action:#selector(showMenu)];
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(swipeHandler:)];
[self.view addGestureRecognizer:gestureRecognizer];
[self issueLoadRequest];
}
- (void)swipeHandler:(UIPanGestureRecognizer *)sender
{
[[self sideMenu] showFromPanGesture:sender];
}
- (void)segmentedControlChangedValue:(HMSegmentedControl *)segmentedControl1 {
[self issueLoadRequest];
}
- (void)segmentedControlSelectedIndexChanged:(id)sender
{
[self issueLoadRequest];
}
#pragma mark -
#pragma mark Button actions
- (void)showMenu
{
[[self sideMenu] show];
}
#pragma mark - Table view data source
- (void)issueLoadRequest
{
// Dispatch this block asynchronosly. The block gets JSON data from the specified URL and performs the proper selector when done.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://my-site/pictureparse.php?name=Name"]];
[self performSelectorOnMainThread:#selector(receiveData:) withObject:data waitUntilDone:YES];
});
}
- (void)receiveData:(NSData *)data {
// When we have the data, we serialize it into native cocoa objects. (The outermost element from twitter is
// going to be an array. I JUST KNOW THIS. Reload the tableview once we have the data.
self.tweets = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
[self.myTableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.tweets.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"PictureJSON";
PictureJSON *cell = (PictureJSON *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"PictureJSON" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// The element in the array is going to be a dictionary. I JUST KNOW THIS. The key for the tweet is "text".
NSDictionary *tweet = [self.tweets objectAtIndex:indexPath.row];
NSLog(#"%#", [cell class]);
cell.instaImage = [tweet objectForKey:#"link"];
cell.titleLabel.text = [tweet objectForKey:#"title"];
cell.timeLabel.text = [tweet objectForKey:#"published"];
return cell;
}
But when I launch my app I get this error:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<PicturesViewController 0x758bf70> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key instaImage.'
My JSON-file looks like this:
[
{
"link": "http://link.com/picture.jpg",
"title": "title",
"published": "0:12 PM 21/10"
},
{
"link": "http://link.com/picture.jpg",
"title": "title",
"published": "0:09 AM 21/10"
}
]
What am I doing wrong?
I think you have to check the property instaImage. I think you are accessing the property that you have not defined in nib.
Fist try to debug this . From the crash log I think you are doing wrong with the custom cell . first check your connection of the PictureJSON . and check your file owner it should be your custom cell. You can confirm this using breakpoint . if you get error while cell creation then above is the solution .
I think the problem is not with your JSON serialization, from your log this crash because of your static NSString *simpleTableIdentifier = #"PictureJSON";
Make sure, you have assigned your custom cell with this identifier !

ios tableviews and json arrays

This has been baffling me for a wile
I am successfully populating an array from a json call but the table view I want to poulate is not happening as the .
Can anyone see why?
I have tried a good few things but the array getting passed to the tableView is not getting populated with successfully retrieve json values
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
self.responseData = nil;
NSArray* categories = [(NSDictionary*)[responseString JSONValue] objectForKey:#"categories"];
[responseString release];
//fetch the data
for (NSDictionary* item in categories) {
NSString* c = [item objectForKey:#"CATEGORY_NAME"];
[self.tableViewArray addObject:[NSString stringWithFormat:#"%#", c]];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self loadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [tableViewArray count];
}
- (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];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Configure the cell.
NSInteger rowNumber = indexPath.row;
NSString *stateName = [tableViewArray objectAtIndex:rowNumber];
cell.textLabel.text = stateName;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *message = [NSString stringWithFormat:#"You selected %#",[self.tableViewArray objectAtIndex:indexPath.row]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert" message: message delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
}
EDIT
My .h is
#interface Medical_MeetingsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
NSMutableArray *tableViewArray;
NSMutableData *responseData;
IBOutlet UITableView *tableViewCat;
}
#property (nonatomic, retain) NSMutableArray *tableViewArray;
#property (retain, nonatomic) NSMutableData *responseData;
-(IBAction)loadData;
#end
is this correct?
Two things:
In the designer, do you have your TableView connected via an IBOutlet? This reference is necessary so that your code can send it instructions.
Second, I don't see you calling [tableview reloadData] anywhere, you'll need to call that after you finish gathering the data.

EXC_BAD_ACCESS crash when switching back and forth between views

I'm getting a EXC_BAD_ACCESS crash when switching back and forth between views. I'm having a problem finding the cause of this crash. In the simulator it always goes back to the main.m file and reports the crash in it.
But on my device the EXC_BAD_ACCESS show up on my custom UITableViewCell when I release it in the dealloc method. If I enable NSZombieEnabled my app doesn't crash at all.
Here is the .h file
#import <UIKit/UIKit.h>
#define kWinsAmountTagValue 2 // how many wins you have
#define kWinningsAmountTagValue 3 // how much money you won
#interface MyStatsViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource,
UINavigationBarDelegate, UINavigationControllerDelegate>{
NSArray *list;
UITableView *theTable;
UITableViewCell *theCell;
}
#property (nonatomic, retain) NSArray *list;
#property (nonatomic, retain) IBOutlet UITableView *theTable;
#property (nonatomic, retain) IBOutlet UITableViewCell *theCell;
// dealloc and cleanup
-(void) dealloc;
// misc methods
-(void)loadData;
// demo data
-(NSArray *)tableData;
#end
Here is my .m file
#import "MyStatsViewController.h"
#implementation MyStatsViewController
#synthesize list;
#synthesize theTable;
#synthesize theCell;
#pragma mark - dealloc and cleanup
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
NSLog(#"Memory Warning");
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.list = nil;
self.theTable = nil;
self.theCell = nil;
}
- (void)dealloc
{
[super dealloc];
[list release];
[theTable release];
[theCell release];
}
#pragma mark - misc methods
-(void) loadData
{
self.list = [self tableData];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
-(void)viewWillAppear:(BOOL)animated
{
[self loadData];
[theTable reloadData];
}
#pragma mark - Table Data Source Methods
-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [list count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier =#"MyStatsCustomCellIdentifer";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
NSUInteger row = [indexPath row];
if (cell == nil) {
if (row == [list count] -1) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
} else {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MyStatsCustomCell"
owner:self
options:nil];
if ([nib count] > 0) {
cell = self.theCell;
} else {
NSLog(#"failed to load MyStatsCustomCell");
}
}
}
// Add custom stuff here for rows
//cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if (row == [list count] -1) {
cell.textLabel.text = [list objectAtIndex:row];
} else {
UILabel *prizeLevel = (UILabel *)[cell viewWithTag:kPrizeLevelTagValue];
prizeLevel.text = [[list objectAtIndex:row] objectForKey:#"prizeLevel"];
UILabel *winsAmount = (UILabel *)[cell viewWithTag:kWinsAmountTagValue];
winsAmount.text = [[list objectAtIndex:row] objectForKey:#"winsAmount"];
UILabel *winningsAmount = (UILabel *)[cell viewWithTag:kWinningsAmountTagValue];
winningsAmount.text = [[list objectAtIndex:row] objectForKey:#"winningsAmount"];
}
//NSLog(#"theCell Retain: %i",[theCell retainCount]);
return cell;
}
#pragma mark - Table View Delegate Methods
-(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - demo data
-(NSArray *)tableData
{
NSArray *prizeLevels = [[NSArray alloc] initWithObjects:
#"6-of-6", #"5-of-6", #"4-of-6",#"3-of-6", nil];
NSArray *winsAmount = [[NSArray alloc] initWithObjects:
#"0", #"0", #"2", #"100", nil];
NSArray *winngingsAmount = [[NSArray alloc] initWithObjects:
#"$0",#"$0", #"$45.50",#"$125.00", nil];
NSMutableArray *myGames = [[[NSMutableArray alloc] init] autorelease];
for (int i = 0; i < [prizeLevels count]; i++) {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:[prizeLevels objectAtIndex:i] forKey:#"prizeLevel"];
[dict setObject:[winsAmount objectAtIndex:i] forKey:#"winsAmount"];
[dict setObject:[winngingsAmount objectAtIndex:i] forKey:#"winningsAmount"];
[myGames addObject:dict];
[dict release];
}
[prizeLevels release];
[winsAmount release];
[winngingsAmount release];
[myGames addObject:#"Spent: $1250.00"];
return myGames;
}
#end
Any help would be appreciated.
It is a good practice to clean up class's own variables before calling the super's destructor. A lot more details can be found here: Why do I have to call super -dealloc last, and not first?.

Resources