UITableView crash on scroll - iphone

Whenever i scroll my UITableView, it looks at an array to find out what to fill the next cell with, but the array is empty, causing a crash, and appears to have been released somehow. Here is my code:
.h
#interface HomeViewController : UITableViewController {
NSArray *vaults;
}
#property (retain) NSArray *vaults;
#end
.m
#import "HomeViewController.h"
NSString *vaultsPath;
#implementation HomeViewController
#synthesize vaults;
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
vaultsPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Vaults"];
NSFileManager *fileManager = [NSFileManager defaultManager];
self.vaults = [fileManager contentsOfDirectoryAtPath:vaultsPath error:nil];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.vaults 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] autorelease];
}
NSString *dictionaryPath = [NSString stringWithFormat:#"%#/%#",
vaultsPath,
[self.vaults objectAtIndex:indexPath.row]]; //Crashes at this line, with the self.vaults array now empty.
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:dictionaryPath];
cell = [AHCellCreation createCellWithDictionary:dictionary Cell:cell];
return cell;
}
- (void)dealloc
{
[super dealloc];
[self.vaults release];
}
#end
Any ideas?

My guess is the app crashes when you try to access the value of vaultsPath, which must be deallocated. Because the table view row count is based on the number of elements in the array, the method returning the cells, won't be called if there isn't any element in.
Try to retain the value assigned to vaultsPath, and don't forget to release it later.

Related

TableViewController not showing json data

I'm a beginner and I've read everything on StackOverflow about my problem - my app with json data doesn't show anything on TableViewController. I'm probably missing something obvious, but the help is appreciated very very much. (I'm using the latest Xcode 5 DP, if it's important).
TableVC.h
#interface TableVC : UITableViewController <UITableViewDataSource, UITableViewDelegate>
#property (strong, nonatomic) NSDictionary *kinos;
#property (retain, nonatomic) UITableView *tableView;
-(void)fetchKinos;
#end
And the TableVC.m file is
#interface TableVC ()
#end
#implementation TableVC
- (void)viewDidLoad
{
[self fetchKinos];
[self.tableView reloadData];
[super viewDidLoad];
}
-(void)fetchKinos {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.adworldmagazine.com/json.json"]];
NSError *error;
_kinos = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _kinos.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"KinoCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//[self configureCell:cell atIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSArray *entities = [_kinos objectForKey:#"entities"];
NSDictionary *kino = [entities objectAtIndex:indexPath.row];
NSDictionary *title = [kino objectForKey:#"title"];
NSString *original = [title objectForKey:#"original"];
NSString *ru = [title objectForKey:#"ru"];
cell.textLabel.text = original;
cell.detailTextLabel.text = ru;
return cell;
}
#end
Your JSON response dictionary contains an array of entities whose count needs to be returned from the table view method.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[self.kinos objectForKey:#"entities"] count];
}
Also, a suggestion, when you declare strong properties, try to access them as self.propertyName instead of accessing the ivar like _propertyName.
Hope that helps!
I accessed your url- http://www.adworldmagazine.com/json.json on my browser.
The response returns a JSON with root: dictionary.
So,
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _kinos.count;
}
wont work.
Use this instead:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_kinos objectForKey:#"entities"].count;
}

UITableView cell returning nil property values

I have the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row==0)
{
static NSString *CellID = #"FlourishCustomCell";
FlourishCustomCell *cell = (FlourishCustomCell *) [tableView dequeueReusableCellWithIdentifier:CellID];
if (cell == nil) {
cell = [[[FlourishCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID] autorelease];
cell.frame = CGRectMake(0, 0.0, 292.0, 30);
}
id <NSFetchedResultsSectionInfo> sectionInfo =
[[appDelegate.fetchedResultsController sections] objectAtIndex:indexPath.section];
NSLog(#"DATE:%#", [sectionInfo name]); //Output: March 25
cell.dateLabel.text=[sectionInfo name];
NSLog(#"header cell:%#", cell.dateLabel.text); //Output:header cell:(null)
return cell;
}
else {
static NSString *CellIdentifier = #"IdeaCustomCell";
IdeaCustomCell *cell = (IdeaCustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[IdeaCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.frame = CGRectMake(0, 0.0, 292.0, 70);
}
[self configureCell:cell atIndexPath:[self newIndexPathForIndexPath:indexPath]];
return cell;
}
}
The cells display and work fine for the else part (the IdeaCustomCell), but for some extremely frustrating reason, when I set the dateLabel of the FlourishCell, and then immediately try to access that value, I get a null value, even though I just set it! And the cell doesn't display on screen.
I tried overriding the setter method for dateLabel in the FlourishCustomCell class, and I put an NSLog statement there, but it never gets called for some reason.
I have absolutely no idea what could be causing this. I mean I'm allocating right then and there, but it's still giving me null. Any ideas?
You need to initialize the label
Solution 1: Initializing cell in code
#interface FlourishCustomCell : UITableViewCell
#property (nonatomic, retain) UILable * dateLabel;
#end
#implementation FlourishCustomCell
#synthesize dateLabel = _dateLabel;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])
{
_dateLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,0,300,50)];
[self.contentView addSubview:_dateLabel]
}
return self;
}
#end
Solution 2: Initializing cell from nib
#interface FlourishCustomCell : UITableViewCell
#property (nonatomic, retain) UILable * dateLabel;
#end
#implementation FlourishCustomCell
#synthesize dateLabel = _dateLabel;
- (id)init
{
self = [[[[NSBundle mainBundle] loadNibNamed:#"YOUR_NIB_NAME" owner:nil options:nil]
lastObject]
retain];
return self;
}
#end
EDIT: oops, forgot to return self on init method, updated the answer
i had the same problem when using nibs, this worked for me
- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"Cell";
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
NSString* nibFile = #"NibForCell";
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed: nibFile owner:nil options: nil];
cell = [topLevelObjects objectAtIndex: 0];
}
cell.cellText.text = #"test";
return cell;
}
just make sure you set the reuse identifier in the nib's properties

Setting textLabel.text in UITableView using JSON data

I will preface the question with I am new to iOS and could use a little push. I have been trying to figure this out for a few days and fear I am not able to figure out the solution out of my frustration. It is my hope that some new eyes backed with experience will be able to help me out with this.
I have a JSON file that I want to use for various portions of my application. The file can be viewed at https://raw.github.com/irong8/stronger-nation-data/master/data.json for reference.
I am using Storyboards and want to accomplish this using the built in JSON support of iOS5. I created a new TableViewController subclass and have included the code below.
Here is my .h file
#import <UIKit/UIKit.h>
#interface StateTableViewController : UITableViewController
{
NSArray *StateList;
}
#property (nonatomic, retain) NSArray *StateList;
- (void) buildStateList;
#end
Here is my .m file
#import "StateTableViewController.h"
#implementation StateTableViewController
#synthesize StateList;
- (void)buildStateList {
NSString *jsonFile = [ [NSBundle mainBundle] pathForResource:#"data" ofType:#"json" ];
NSError *jsonError = nil;
NSData *jsonData = [NSData dataWithContentsOfFile:jsonFile options:kNilOptions error:&jsonError ];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&jsonError];
NSArray *jsonArray = [json objectForKey:#"states"];
self.StateList = jsonArray;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self buildStateList];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [StateList 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.text = [NSString stringWithFormat:#"%d", indexPath.row];
return cell;
}
I can loop through the StateList array using the following and see the state names I am looking for.
for (NSString *element in StateList) {
NSLog(#"element: %#", element);
}
When I load this view, a TableView is loaded with 50 rows (as expected as there are 50 state records in my data file) and each row is numbered 0-49. I am having trouble figuring out how to access the state name in my StateList array.
Any help along the way would be much appreciated!
You would populate your tableview's cells with data in cellForRow... Here is a slight modification of the default implementation in new projects:
- (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 = [StateList objectAtIndex:rowNumber];
cell.textLabel.text = stateName;
return cell;
}
EDIT The reason your app is now crashing is the object for the key "states" is a dictionary (as it should be according to the json at the link you posted) and you cannot simply cast it to an array. You can, however, ask the dictionary for an array of all of the keys. Which in this case will be the state names.
Change this line of code in buildStateList:
NSArray *jsonArray = [[json objectForKey:#"states"] allKeys];

UITableView abcd list indexing

I need to implement the abcd list indexing in the below table view right side.when i am clicking on a/b/c etc table view need to show the entries according to that for sorting like iphone contacts .may i know what are all
the changes i need for it.is need to create sections for that?please any one explain me
any solution.
I have an class named as "myClass" which contains the properties iD, name and imageURL.
image url holds the photolibrary alasset url.
myClass.h
#interface myClass: NSObject {
NSInteger iD;
NSString *name;
NSString *imageURL;
}
#property (nonatomic, assign) NSInteger iD;
#property (nonatomic, assign) NSString *name;
#property (nonatomic, assign) NSString *imageURL;
myClass.m
#implementation myClass
#synthesize iD;
#synthesize name;
#synthesize imageURL;
#end
So I added 50 image details with iD, name, imageURL as myClass objects in to an NSMutableArray named as *BundleImagesArray *
i displayed it in a table view. my code is:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
//getting all image details with iD,name,imageURL as **myClass** objects
BundleImagesArray = [staticDynamicHandler getImageFromBundle];
int count = [BundleImagesArray count];
for (int i = 0; i<count; i++) {
//this array for easy scrolling after first time the table is loaded.
[imageCollectionArrays addObject:[NSNull null]];
}
return count;
}
cellForRowAtIndexPath
- (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] autorelease];
}
//removing all the subviews
if ([cell.contentView subviews]) {
for (UIView *subview in [cell.contentView subviews]) {
[subview removeFromSuperview];
}
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell setAccessoryType:UITableViewCellAccessoryNone];
myClass *temp = [BundleImagesArray objectAtIndex:indexPath.row];
//adding image view
UIImageView *importMediaSaveImage=[[[UIImageView alloc] init] autorelease];
importMediaSaveImage.frame=CGRectMake(0, 0, 200,135 );
[cell.contentView addSubview:importMediaSaveImage];
//adding image label
UILabel *sceneLabel=[[[UILabel alloc] initWithFrame:CGRectMake(220,0,200,135)] autorelease];
sceneLabel.font = [UIFont boldSystemFontOfSize:16.0];
sceneLabel.textColor=[UIColor blackColor];
[cell.contentView addSubview:sceneLabel];
sceneLabel.text = temp.name;
if([imageCollectionArrays objectAtIndex:indexPath.row] == [NSNull null]){
//getting photlibrary image thumbnail as NSDAta
NSData *myData = [self photolibImageThumbNailData::temp.imageURL]
importMediaSaveImage.image =[UIImage imageWithData:myData ];
[imageCollectionArrays replaceObjectAtIndex:indexPath.row withObject:importMediaSaveImage.image];
} else {
importMediaSaveImage.image = [imageCollectionArrays objectAtIndex:indexPath.row];
}
temp = nil;
return cell
}
*Note:*
i done it using the following way
1.Number of sections-
inside this we are getting the label array and then calling the method countArrayWords whihc will count the words and
the alphabets starting from a particular word.
2.Title for headerin section-
Used for gettting the headers for the sections.Currently we are not using this methd as it will not look good when we are having
no data on the table view.
3.number of rows in section-
in this we are calling the method countArrayWords if the sectio=0.
4.cell for row at index path-
this is the method in which we are calculating a variable known as h through which we are using to bind the images to the table
view.
However the Tableview performence is too slow with 1000 images
An easy way to handle this is to create 2 arrays, one of sections, and another of section titles. You can then populate these from your sorted array of MyClass'es in your init method (initWithObjects: , say)
- (id) initWithObjects: (NSArray *) myObjectsArray
{
self = [super initWithNibName: <your-nib-name> bundle: nil];
if (self) {
self.sections = [NSMutableArray array];
self.sectionTitles = [NSMutableArray array];
for (MyClass * object in self.myObjectsArray) {
NSMutableArray * section = [self.sections lastObject];
if (!section || ![[[[section lastObject] name] substringToIndex: 1] isEqualToString: [object.name substringToIndex: 1]]) {
// Create a new section on change of first character
[self.sections addObject: [NSMutableArray array]];
[self.sectionTitles addObject: [object.name substringToIndex: 1]];
}
[[self.sections lastObject] addObject: object];
}
}
return self;
}
Then your datasource methods are
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.sections count];
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[self.sections objectAtIndex: section] count];
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Create cell
MYClass * object = [[self.sections objectAtIndex: indexPath.section] objectAtIndex: indexPath.row];
//Configure cell
return cell;
}
- (NSArray *) sectionIndexTitlesForTableView:(UITableView *)tableView
{
return self.sectionTitles;
}

How to copy pasteboard items into a table?

I have got an assignment here where I am supposed to
create an application, which copies the all the pasteboard items into
a table, that drills down into a detail view of said pasteboard item
.
Below, I give you my code of the RootViewController.m file. The program does not work and gives me an error of SIGABRT in this line cell.textLabel.text = cellValue;.
Could you tell me please, what could be possibly wrong here and thank you in advance.
#import "RootViewController.h"
#implementation RootViewController
#synthesize detailsViewController;
NSArray* pasteBoardItems;
- (void)viewDidLoad
{
// Get a reference to the system pasteboard
UIPasteboard* pasteBoard = [UIPasteboard generalPasteboard];
NSLog(#"%#", pasteBoard.items);
pasteBoardItems = [pasteBoard.items valueForKey:#"public.utf8-plain-text"];
pasteBoardItems = [pasteBoard.items valueForKey:#"public.item (kUTTypeItem)"];
self.navigationItem.title = #"Pasteboard";
[super viewDidLoad];
}
- (void)dealloc
{
[pasteBoardItems release];
[super dealloc];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [pasteBoardItems count];
}
// Customize the appearance of table view cells.
- (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] autorelease];
}
NSString *cellValue = [pasteBoardItems objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
// Configure the cell.
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
NSString *rowValue = [pasteBoardItems objectAtIndex:row];
NSString *message = [[NSString alloc] initWithFormat:#"You have selected \"%#\"",rowValue];
if(self.detailsViewController == nil){
DetailsViewController *d = [[DetailsViewController alloc] initWithNibName:#"DetailsViewController" bundle:[NSBundle mainBundle]];
self.detailsViewController = d;
[d release];
}
[self.detailsViewController initWithTextSelected:message];
[self.navigationController pushViewController:self.detailsViewController animated:YES];
}
#end
SIGABRT in most cases means that you want to access released object.
In your case, I suggest to add line [pasteBoardItems retain]; at the end of - (void)viewDidLoad method.