Unable to reload UITableView after connectionDidFinishLoading completes - ios

I am downloading and parsing JSON objects to build a "news feed" to populate a UITableView. The very last line of code I have in the connectionDidFinishLoading delegate method is:
[tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
However, my break points in the - (UITableViewCell *)tableView:(UITableView *)mytableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method are not hit. (They are hit when the app first launches)
So for whatever reason even though I am calling the reloadData on the main thread; it doesn't appear to be firing. I tried just [tableView reloadData] and that did not work.
Here is my connectionDidFinishLoading method:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSArray *publicTimeline = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
NSUInteger newsStreamCount = [publicTimeline count];
// Initialize the collection and the dictionary
newsItemManager.newsItemCollection = [[NSMutableArray alloc] initWithCapacity:newsStreamCount];
NSMutableArray *dictOfNewsItems = [[NSMutableArray alloc] initWithCapacity:newsStreamCount];
// From the JSON object, parse out the individual news item JSON objects and
// put them into a dictionary.
for (int i = 0; i < newsStreamCount; i++)
{
NSDictionary *item = [publicTimeline objectAtIndex:i];
[dictOfNewsItems addObject:item];
}
// For each news item JSON object, extract out the information we need for our
// news manager class
for (int i = 0; i < newsStreamCount; i++)
{
NSString *userName = [[dictOfNewsItems objectAtIndex:i] valueForKey:#"Title"];
NSString *message = [[dictOfNewsItems objectAtIndex:i] valueForKey:#"Content"];
NSString *imgUrl = [[dictOfNewsItems objectAtIndex:i] valueForKey:#"https://si0.twimg.com/logo_normal.jpg"];
NewsItem *newsItem = [[NewsItem alloc] initWithBasicInfo:userName :message :imgUrl];
[newsItemManager.newsItemCollection addObject:newsItem];
}
[tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
}
Here is my header file:
#import <UIKit/UIKit.h>
#interface NewsViewController : UITableViewController
#property (nonatomic, retain) NSMutableArray* newsItemArray;
#property (nonatomic, retain) NSMutableData *responseData;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#end
Here is my implementation:
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
self.title = #"News";
//self.newsItemArray = [[NSMutableArray alloc] initWithObjects:#"One", #"Two", #"Three", nil];
tableView.rowHeight = 75.0;
responseData = [NSMutableData data];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://blah.com/api/news"]];
(void)[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
Thanks,
Flea

If your connectionDidFinish... method is inside your tableViewController class, maybe you just need
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];

The overall problem was my newsItemManager.newsItemCollection was not being initialized properly and was returning null the entire time, thus when the UITableView was trying to load data; there was nothing to load.
I thought I had checked for this but one of those problems of staring at the computer all day and missing the obvious.

Related

Cells disappear when scroll down in my UITableView

When I scroll down in my tableView some contents of cells disappear (labels and imageViews).
My code:
-(void)viewWillAppear:(BOOL)animated{
[comentarios removeAllObjects];
NSString *lookup=[NSString stringWithFormat:#"http://my.url"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:lookup]];
[request setHTTPMethod:#"GET"];
NSError *error = nil; NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSMutableArray *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSLog(#"%#",jsonDict);
for (int i=0; i<[jsonDict count]; i++) {
Comentario *come=[[Comentario alloc] init];
come.nick=[[jsonDict objectAtIndex:i] objectForKey:#"nick"];
come.comment=[[jsonDict objectAtIndex:i] objectForKey:#"content"];
come.avatar=[[jsonDict objectAtIndex:i] objectForKey:#"color"];
[comentarios addObject:come];
}
[self reloadInputViews];
[self.comentariosTableView reloadData];
}
and
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if( cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: CellIdentifier];
}
// Display recipe in the table cell
UIImageView *avatar = (UIImageView *)[cell viewWithTag:100];
avatar.image = [UIImage imageNamed:[[comentarios objectAtIndex:indexPath.row] avatar]];
UILabel *nick = (UILabel *)[cell viewWithTag:101];
nick.text =[[comentarios objectAtIndex:indexPath.row] nick];
UILabel *comment = (UILabel *)[cell viewWithTag:102];
comment.text = [[comentarios objectAtIndex:indexPath.row] comment];
UIButton *sinvoto = (UIButton *)[cell viewWithTag:103];
UIButton *ticket = (UIButton *)[cell viewWithTag:104];
return cell;
}
I can't see the mistake, please help me.
Thank you in advance
EDIT Nª1
just changed this
ViewController.m
#import "ViewController.h"
#import "SimpleTableCell.h"
#interface ViewController (){
NSMutableArray *comentarios;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.comenatrioTableView.delegate=self;
self.comenatrioTableView.dataSource=self;
self.automaticallyAdjustsScrollViewInsets = NO;
UIImage *plus=[[UIImage imageNamed:#"megafono.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
self.navigationItem.leftBarButtonItem=[[UIBarButtonItem alloc] initWithImage:plus style:UIBarButtonItemStylePlain target:self action:#selector(comenta:)];
self.navigationController.navigationBar.barTintColor=[UIColor colorWithRed:204.0/255.0 green:0.0/255.0 blue:00.0/255.0 alpha:1.0f];
comentarios=[[NSMutableArray alloc] init];
[self reloadInputViews];
}
-(void)viewWillAppear:(BOOL)animated{
[comentarios removeAllObjects];
NSString *lookup=[NSString stringWithFormat:#"http://myURL"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:lookup]];
[request setHTTPMethod:#"GET"];
NSError *error = nil; NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSMutableArray *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSLog(#"%#",jsonDict);
for (int i=0; i<[jsonDict count]; i++) {
Comentario *come=[[Comentario alloc] init];
come.nick=[[jsonDict objectAtIndex:i] objectForKey:#"nick"];
come.comment=[[jsonDict objectAtIndex:i] objectForKey:#"content"];
come.avatar=[[jsonDict objectAtIndex:i] objectForKey:#"color"];
[comentarios addObject:come];
}
[self reloadInputViews];
}
-(void)viewDidAppear:(BOOL)animated{
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [comentarios count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 110;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier forIndexPath:indexPath];
Comentario *comentario=[[Comentario alloc] init];
comentario =[comentarios objectAtIndex:indexPath.row];
cell.avatar.image=[UIImage imageNamed:[comentario avatar]];
cell.nick.text=[comentario nick];
cell.comment.text =[comentario comment];
return cell;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
-(void)comenta:(id)sender{
[self performSegueWithIdentifier:#"goComment" sender:self];
}
#end
and ViewController.h
#import <UIKit/UIKit.h>
#import "Comentario.h"
#interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *comenatrioTableView;
#end
Edit Nª3
The proble is when I scroll down, the information of cells become nil but comentarios Array have the information.
Edit Nª4
here is the project https://github.com/QuimeraKoke/BANG-
I have a couple of other suggestions that will improve your code.
You have to call super in viewDidAppear and viewWillAppear methods:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:YES];
}
Instead of using:
Comentario *comentario = [[Comentario alloc] init];
comentario = [comentarios objectAtIndex:indexPath.row];
with:
Comentario *comentario = [comentarios objectAtIndex:indexPath.row];
Finally, you should check your dataSource:
for (int i=0; i<[jsonDict count]; i++) {
Comentario *come = [[Comentario alloc] init];
come.nick = [[jsonDict objectAtIndex:i] objectForKey:#"nick"];
come.comment = [[jsonDict objectAtIndex:i] objectForKey:#"content"];
come.avatar = [[jsonDict objectAtIndex:i] objectForKey:#"color"];
[comentarios addObject:come];
NSLog(#"nick = %#, comment = %#, avatar = %#", come.nick, come.comment, come.avatar);
}
EDIT:
Instead of using:
#interface Comentario : NSObject
#property (weak,nonatomic) NSString *nick;
#property (weak,nonatomic) NSString *comment;
#property (weak,nonatomic) NSString *avatar;
#end
you should use:
#interface Comentario : NSObject
#property (copy,nonatomic) NSString *nick;
#property (copy,nonatomic) NSString *comment;
#property (copy,nonatomic) NSString *avatar;
#en
Your problem has been resolved.
Copy
copy is required when the object is mutable. Use this if you need the
value of the object as it is at this moment, and you don't want that
value to reflect any changes made by other owners of the object. You
will need to release the object when you are finished with it because
you are retaining the copy.
Weak
weak is similar to strong except that it won't increase the reference
count by 1. It does not become an owner of that object but just holds
a reference to it. If the object's reference count drops to 0, even
though you may still be pointing to it here, it will be deallocated
from memory.
This is a good website to learn about strong and weak for iOS 5.
http://www.raywenderlich.com/5677/beginning-arc-in-ios-5-part-1
In addition to the above problem,your constrains of the SimpleTableCell is also incorrect:
You should go to the Main.storyboard and check it.(In Interface Builder Select the Compact Width and Compact Height Size Class)
The tableView:cellForRowAtIndexPath: code you're using is pretty old.
I'd suggest creating a custom UITableViewCell class, with properties for your labels, image, and buttons.
#interface MyTableViewCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel *nick;
#property (nonatomic, weak) IBOutlet UILabel *comment;
#property (nonatomic, weak) IBOutlet UIImageView *avatar;
#property (nonatomic, weak) IBOutlet UIButton *sinvoto;
#property (nonatomic, weak) IBOutlet UIButton *ticket;
#end
In your storyboard, set that cell's class to your custom tableViewCell, and connect its IBOutlets to the storyboard cell's labels, image, and buttons. This will eliminate having to use tags.
Change the dequeueReusableCellWithIdentifier: call to:
MyTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
This will always return a cell, so you will never have to check for nil.
Now you can directly set the cell's properties:
cell.avatar.image = [UIImage imageNamed:[[comentarios objectAtIndex:indexPath.row] avatar]];
cell.nick.text =[[comentarios objectAtIndex:indexPath.row] nick];
cell.comment.text = [[comentarios objectAtIndex:indexPath.row] comment];
Update:
This line (has to do with changing the keyboard) is unnecessary and can be removed:
[self reloadInputViews];
Is there a reason why you are using a UIViewController (with a tableView that you added), instead of simply using a UITableViewController?
The UITableViewController knows how to adjust its insets to account for top and bottom bars (and you would set its automaticallyAdjustsScrollViewInsets to YES).
After making the changes that Banning suggests, you may be ok. I can't see any other reason why the cells would be blank after scrolling.
If it's still happening, you should post your Comentario class, so we can see if an issue with that code is affecting the stored data.

How to customize the position in Table View cell iOS

Hi everyone I would like to ask I want to show JSON data and customize the position for image and text in Table View.
how can I do like that? please advice me.
You can take a look at the Image Url.
for image 1 it is the result as I've parsing from JSON.
Image 1
for image 2 it is my goal.
Image 2
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
#property (retain, nonatomic) IBOutlet UITableView *myTableView;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *myObject;
// A dictionary object
NSDictionary *dict;
// Define keys
NSString *galleryid;
NSString *name;
NSString *titlename;
NSString *thumbnail;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Define keys
galleryid = #"GalleryID";
name = #"Name";
titlename = #"TitleName";
thumbnail = #"Thumbnail";
// Create array to hold dictionaries
myObject = [[NSMutableArray alloc] init];
NSData *jsonData = [NSData dataWithContentsOfURL:
[NSURL URLWithString:#"MY_JSON_URL"]];
id jsonObjects = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
// values in foreach loop
for (NSDictionary *dataDict in jsonObjects) {
NSString *strGalleryID = [dataDict objectForKey:#"GalleryID"];
NSString *strName = [dataDict objectForKey:#"Name"];
NSString *strTitleName = [dataDict objectForKey:#"TitleName"];
NSString *strThumbnail = [dataDict objectForKey:#"Thumbnail"];
dict = [NSDictionary dictionaryWithObjectsAndKeys:
strGalleryID, galleryid,
strName, name,
strTitleName, titlename,
strThumbnail, thumbnail,
nil];
[myObject addObject:dict];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return myObject.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// Use the default cell style.
cell = [[[UITableViewCell alloc] initWithStyle : UITableViewCellStyleSubtitle
reuseIdentifier : CellIdentifier] autorelease];
}
NSDictionary *tmpDict = [myObject objectAtIndex:indexPath.row];
NSURL *url = [NSURL URLWithString:[tmpDict objectForKey:thumbnail]];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
cell.imageView.image = img;
cell.textLabel.text = [tmpDict objectForKey:name];
cell.detailTextLabel.text= [tmpDict objectForKey:titlename];
//[tmpDict objectForKey:memberid]
//[tmpDict objectForKey:name]
//[tmpDict objectForKey:titlename]
//[tmpDict objectForKey:thumbnail]
return cell;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc {
[_myTableView release];
[super dealloc];
}
#end
It will be easy if creating custom TableviewCell (subclass to UITableViewCell) to display the array of objects you have, than using UITableViewCell to display as you desired.
Create custom UITableviewCell with xib or with storyboard and create properties as you needed and give the position and styling for the cell elements.
Bind data for the cells in your cellForRowAtIndexPath method.
For more information, refer: this and this for more info

My view does not update

My ParseXML method reads the value of NSNumber, which can be incremented by a click of a button.
My ParseXML method has 240 objects, each 8 have an ID from 1 to 30.
The idea is that if i increment the NSNumber from 1 to 2, it refreshes my view and grabs the 8 objects that match the ID and displays it in my view.
That is exactly what is not doing.
.h
#interface FixturesController : UITableViewController
{
NSMutableData *_responseDataFixtures;
int goUp;
NSNumber *test;
}
#property (nonatomic, retain) NSArray *tableDataFixtures;
#property (nonatomic, strong) NSMutableArray *roundParser;
#property (nonatomic, strong) NSString *seasonRoundString;
#property (nonatomic, strong) NSNumber *seasonRoundNumber;
- (IBAction)goUpByOne:(UIButton *)sender;
-(void) parseXMLFixtures:(NSNumber *) giveME;
#end
.m
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self parseXMLFixtures:#2];
}
- (void)viewDidLoad
{
[super viewDidLoad];
goUp = 1;
test = [NSNumber numberWithInt:goUp];
}
// this allows me to increment the count of NSNumber.
- (IBAction)goUpByOne:(UIButton *)sender {
goUp++;
test = [NSNumber numberWithInt:goUp];
goUp = [test intValue];
}
-(void) parseXMLFixtures:(NSNumber *) giveME
{
giveME = test;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"There's no going back"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *xmlString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *xml = [NSDictionary dictionaryWithXMLString:xmlString];
NSMutableArray *items = [xml objectForKey:#"Match"];
NSMutableArray *newFixtureObjectArray = [[NSMutableArray alloc] init];
NSNull *nullValue = [NSNull null];
[newFixtureObjectArray insertObject:nullValue atIndex:0];
[newFixtureObjectArray insertObject:nullValue atIndex:1];
for (NSDictionary *dict in items) {
FixturesObject *myFixtures = [FixturesObject fixtureFromXMLDictionary:dict];
[newFixtureObjectArray addObject:myFixtures];
}
///////
_seasonRoundString = [NSString stringWithFormat:#"%d", [giveME intValue]];
_roundParser = [[NSMutableArray alloc]init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"round == %#", _seasonRoundString];
NSArray *filteredArray = [newFixtureObjectArray filteredArrayUsingPredicate:predicate];
_roundParser = [NSMutableArray arrayWithArray:filteredArray];
[_roundParser insertObject:nullValue atIndex:0];
NSLog(#" Objects of Fixtures in my array %#", _roundParser);
/////
[self setTableDataFixtures:_roundParser];
}
Any suggestions? Thank you. I really need this to work so i can go sleep ˆˆ
Have you impleted the UITableViewDelegate, UITableViewDataSource methods yet?
The methods are:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{ }
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { }
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{}
You can follow this tutorial

Retrieving and re-saving an nsmutablearray to nsuserdefaults from a uitableview

I have a uitableview with a list of items populated from a JSON file located locally within the app. Everything works as far as getting the list to the table and the multiple selection of items which when selected (or deselected) are then saved to a nsmutablearray.
The problem is when the user leaves the view and returns and selects another item (or deselects a currently selected item). At this point the mutable array is then empty.
I'm not sure if the nsuserdefaults saving of the mutable array is the problem. it saves it fine but then when the view reappears (the mutable array's value is fine at this point) and the user touches a table row the array is null once more.
my .h file:
#interface CategoriesViewController : UITableViewController {
NSMutableArray *_selectedItems;
NSString *filePath;
NSString *string;
}
// arForTable array will hold the JSON results from the api
#property (nonatomic, retain) NSArray *arForTable;
#property (nonatomic, retain) NSMutableArray *categorySelected;
#property (nonatomic, retain) NSString *jsonStringCategory;
#property(nonatomic, retain) UIView *accessoryView;
#end
my .m file:
#implementation CategoriesViewController
#synthesize arForTable = _arForTable;
- (void)viewDidLoad
{
[super viewDidLoad];
self.categorySelected = [[NSMutableArray alloc] init];
[self reloadMain];
// assignment reference so don't release
_selectedItems = [(AppDelegate *)[[UIApplication sharedApplication] delegate] selectedCategories];
self.tableView.hidden = NO;
}
-(void) reloadMain {
// countrySaved value from NSUserDefaults
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
NSString *countryString = [defaults stringForKey:#"selectedCountryTableString"];
NSString *cityString = [defaults stringForKey:#"selectedCityTableString"];
NSLog(#"countrystring from category is %#", countryString);
NSLog(#"citystring from category is %#", cityString);
// getting path to the file
if ([defaults stringForKey:#"selectedCountryTableString"] == NULL) {
filePath = [[NSBundle mainBundle] pathForResource:#"categoriesit" ofType:#"json"];
} else if ([countryString isEqualToString:#"UK"]) {
filePath = [[NSBundle mainBundle] pathForResource:#"categoriesuk" ofType:#"json"];
} else if ([countryString isEqualToString:#"Italy"]) {
filePath = [[NSBundle mainBundle] pathForResource:#"categoriesit" ofType:#"json"];
} else if ([countryString isEqualToString:#"Spain"]) {
filePath = [[NSBundle mainBundle] pathForResource:#"categorieses" ofType:#"json"];
} else if ([countryString isEqualToString:#"Brazil"]) {
filePath = [[NSBundle mainBundle] pathForResource:#"categoriesbr" ofType:#"json"];
}
NSString *fileContent = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
//NSLog(#"File content: %#", fileContent);
// creating new parser
SBJSON *parser = [[SBJSON alloc] init];
// parsing the first level
NSDictionary *data = (NSDictionary *) [parser objectWithString:fileContent error:nil];
NSDictionary *menu = (NSDictionary *) [data objectForKey:#"menu"];
#ifdef DEBUG
NSLog(#"menu is %#",menu);
#endif
NSMutableArray *itemsTMP = [[NSMutableArray alloc] init];
NSData *jsonData = [NSData dataWithContentsOfFile:filePath];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:nil error:nil];
// NSLog(#"results File test %#",dict);
itemsTMP = [dict objectForKey:#"results"];
// NSLog(#"itemsTMPitemsTMP File test %#",itemsTMP);
self.arForTable = [itemsTMP copy];
[self.tableView reloadData];
}
#pragma mark - Table view data source
- (int)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.arForTable 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.textLabel setFont:[UIFont fontWithName: #"Asap-Bold" size: 14.0f]];
[cell.detailTextLabel setFont:[UIFont fontWithName: #"Asap-Bold" size: 14.0f]];
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];
cell.selectedBackgroundView.backgroundColor = [UIColor colorWithRed:204.0/255.0 green:56.0/255.0 blue:55.0/255.0 alpha:1];
}
UIImageView *cellAccessoryImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"icon-tick.png"]] ;
UIImageView *cellAccessoryNoneImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#""]] ;
if([_selectedItems containsObject:indexPath]){
cell.accessoryView = cellAccessoryImageView;
} else {
cell.accessoryView = cellAccessoryNoneImageView;
}
// Get item from tableData
NSDictionary *item = (NSDictionary *)[_arForTable objectAtIndex:indexPath.row];
// encoding fix
NSString *correctStringTitle = [NSString stringWithCString:[[item objectForKey:#"key"] cStringUsingEncoding:NSISOLatin1StringEncoding] encoding:NSUTF8StringEncoding];
cell.textLabel.text = [correctStringTitle capitalizedString];
NSNumber *num = [item objectForKey:#"id"];
cell.detailTextLabel.text = [num stringValue];
cell.detailTextLabel.hidden = YES;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
if([_selectedItems containsObject:indexPath]){
[_selectedItems removeObject:indexPath];
[self.categorySelected removeObject:[[self.arForTable objectAtIndex:indexPath.row] objectForKey:#"id"]];
string = [self.categorySelected componentsJoinedByString:#","];
[defaults setObject:string forKey:#"selectedCategoryTableString"];
NSLog(#"%# defaults from did select remove categorySelected",[defaults stringForKey:#"selectedCategoryTableString"]);
NSLog(#"%# STRING FROM contains / removeObj",string);
} else {
[_selectedItems addObject:indexPath];
[self.categorySelected addObject:[[self.arForTable objectAtIndex:indexPath.row] objectForKey:#"id"]];
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
string = [self.categorySelected componentsJoinedByString:#","];
[defaults setObject:string forKey:#"selectedCategoryTableString"];
NSLog(#"%# providerSelected from did select add ",self.categorySelected);
NSLog(#"%# STRING FROM contains / addObj",string);
}
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
// [tableView reloadData];
}
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:NO];
[self.navigationController setNavigationBarHidden:YES animated:NO];
self.navigationController.toolbarHidden = YES;
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
// NSLog(#"ALL DEFAULTS %#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
NSLog(#"%# defaults from view appear categorySelected",[defaults stringForKey:#"selectedCategoryTableString"]);
string = [defaults stringForKey:#"selectedCategoryTableString"];
NSLog(#"%# STRING from will appear",string);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
also in the app delegate I have in the .h:
#property (strong, nonatomic) NSMutableArray *selectedCategories;
and in the .m:
`_selectedCategories = [NSMutableArray new];
in the didFinishLaunchingWithOptions: method
just to be clear:
when the view appears again (if I nslog the output) the mutablearray has been saved and is retrieved correctly. the mutable array only clears itself when a tablerow is touched again.
thanks if anyone can help with this. I've been stuck on it for some time...
edit
// DONT EVER EVER EVER EVER EVER EVER DO THIS!!!
// We don't use types as variable names, that is implicit...
// I get it, this is a string, BUT WHAT IS IT A STRING OF, the name
// 'string' does you, and anyone else, no good. Think about all your
// code like you are writing it for someone else, because when you come
// back to it in 6 months, you will be someone else, and you won't know
// what this means
NSString *string;
end edit
I would not be using NSUserDefaults this way. You have already parsed JSON into an archiveable object (NSMutableArray). In viewDidLoad, you should probably try doing something like:
-(void)viewDidLoad
{
// Load the array from a plist file
self.dataYouNeed = [NSMutableArray arrayWithContentsOfFile:#"someFileName.plist"];
// If we got back nil, that file didn't exist, so call 'reloadMain',
// do your parsing there THEN SAVE to a plist using:
//
// [myArray writeToFile:#"someFileName.plist"]
//
if(self.dataYouNeed == nil) [self reloadMain];
// Then do the exact same thing when you try to persist your selection...
// aka do not store a CSV string, just store an Array, and call writeToFile:
// when you want to save, and arrayWithContentsOfFile when you want to read
// it back in
}
On top of that, depending on where your data is coming from, I would move all of your data out of the JSON files and set it up in a plist, then you can ditch all of your parsing code.... :). Basically I am saying this is all a little too complicated for such a simple task, make your own life easier.
edit
You may have an issue with not using 'self.string', simply referring to 'string' is dangerous, you are creating a new reference everytime. This is most likely creating a memory leak. (ARC is not magic, it can not handle ALL memory management for you)
edit
Ok, so re-reading your code, I noticed a few things.
1. Why do you store your CSV string in the 'string' instance var?
This is somewhat redundant. At no point do you ever read from this variable without having set it in the few lines of code before. It should just be an NSString declared with in the scope of the method.
2. Are you expecting '_selectedItems' to have retained your reference to the 'selectedCategories' array on your AppDelegate?
You can not make this assumption, especially without having made a #property declaration. ARC does not know how to handle it and will probably be releasing the reference when you leave the view. The more likely possibility is that you are creating a memory leak every time you set that variable. You can also not guarantee that viewDidLoad will be called again to reset the reference. You should probably be setting this in viewWillAppear.
3. Which NSMutableArray are you experiencing a nil reference to?
If it is '_selectedItems', consider #2. If it is 'categorySelected', this is also probably being released when this view disappears. If this is really what you are trying to persist, then why are you not populating it from the viewDidAppear method. The only thing you do in viewDidAppear is set the 'string' variable (which is never actually read from, like #1 says). Did you mean to set 'categorySelected' here? I believe you meant to get your list from NSUserDefaults, then populate 'categorySelected' using that string's componentsSeparatedByString: method, which returns an array
Every time a user goes to some other view and comes back then
self.categorySelected = [[NSMutableArray alloc] init]; gets executed resulting it to an empty array.
First serialize the array when leaving the view:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:#[#"1",#"2",#"3"]];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"myarray"];
[[NSUserDefaults standardUserDefaults] synchronize];
Then deserialize it when you are back to that view:
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"myarray"];
NSArray *myarray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(#"MYARRAY %#", myarray);
Note: if key is not found then init a new array.
Can you try to change 'retain' to 'strong' here?
#property (nonatomic, retain) NSMutableArray *categorySelected;
I think the issue is, you are setting the selectedItems array in viewDidLoad method. Probably the viewDidLoad is working once.
Just add the following line in your viewWillAppear method:
_selectedItems = [(AppDelegate *)[[UIApplication sharedApplication] delegate] selectedCategories];

UITableView not loading but array is populated

I have a UITableView that I would like to populate with data via a WebAPI. I have everything set up and I can verify that data is returned in JSON format. What I don't understand is why I see that data in my array printed out several times when I use NSLog and also how do I assign this data to the UITableView. I was able to populate the table from the viewDidLoad method but these are hard-coded values. I want to populate the grid with data that is returned from my call to the remote server. This data is available to me in my didReceiveData delegate. What am I doing wrong here?
I have this code in my MasterViewControler.h
#interface MasterViewController : UITableViewController <UITableViewDataSource, UIAlertViewDelegate> {
NSMutableArray *dataArray;
NSMutableArray *categoryNames;
}
Here is an abridged version of what I have in my MasterViewController.m file
NSMutableData* receivedData;
NSString* hostName;
NSInteger portNumber = 9999;
NSMutableDictionary* dictionary;
NSInteger maxRetryCount = 5;
int count = 0;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"Succeeded! Received %d bytes of data",[data length]);
NSError *error = nil;
// Get the JSON data from the website
id result = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if ([result isKindOfClass:[NSArray class]]) {
for (NSArray *item in result)
[dataArray addObject:item];
NSLog(#"%#", dataArray);
}
else {
NSDictionary *jsonDictionary = (NSDictionary *)result;
for(NSDictionary *item in jsonDictionary)
NSLog(#"Item: %#", item);
}}
- (void)viewDidLoad{
[super viewDidLoad];
hostName = [[NSString alloc] initWithString:#"12.34.56.78"];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://%#:%i%#", hostName, portNumber, #"/api/products"]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url cachePolicy: NSURLRequestReloadIgnoringLocalCacheData timeoutInterval: 2];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addNewItem)]; //insertNewObject
self.navigationItem.rightBarButtonItem = addButton;
dataArray = [[NSMutableArray alloc] init];
//[dataArray addObject:#"Apple"];
//[dataArray addObject:#"Mango"];
//[dataArray addObject:#"Orange"];}
Instead of populating the dataArray here I was trying to populate it in the didReceiveData delegate. The dataArray will be allocated but it is almost like I have to reload the UITableView to see the values. I tried that at the end of didReceiveData but I received an error.
First make sure your UITableViewDataSource and UITableViewDelegate are set.
Once the array is populated (in your case, at the end of -(void)connection:didReceiveData:) you'd call [tableView reloadData] to refresh the table.
Then you'd set your cell in:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// If your array is an array of strings, change if applicable
NSString *string = [dataArray objectAtIndex:indexPath.row];
[cell.textLabel setText:string];
}
Your class should implement UITableView's UITableViewDataSource protocol, and then assign itself as the dataSource. Then implement cellForRowAtIndexPath:, which is where you actually use your model array to initialize the cells. When your data is ready, call reloadData on the table view.

Resources