I'm having a problem with my iPhone app crashing when I scroll down on a UITableView. I set NSZombieEnabled to YES, and found out that the NSArray I'm using to fill the table is getting dealloced somehow.
#import "RootViewController.h"
#implementation RootViewController
#synthesize flashsets;
- (void)viewDidLoad
{
//Unrelated code removed from this post
NSString *listofsetsstring = [[NSString alloc]
initWithContentsOfFile:pathtosetsdata
encoding:NSUnicodeStringEncoding
error:&error];
flashsets = [listofsetsstring componentsSeparatedByString:#"\n"];
[super viewDidLoad];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [flashsets 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];
}
// Configure the cell.
NSLog(#"IndexPath.row = %i", indexPath.row);
cell.textLabel.text = [flashsets objectAtIndex:indexPath.row]; <<<< CRASH HERE!!
return cell;
}
#end
I'm getting message sent to deallocated instance 0x4ebae20 at the bolded line. In my .h I used #property (nonatomic, retain) NSArray *flashsets;, I thought the retain part should keep it from deallocating.
How do I keep it from doing this?
Problem is with :
flashsets = [listofsetsstring componentsSeparatedByString:#"\n"];
change it to
flashsets = [[listofsetsstring componentsSeparatedByString:#"\n"] retain];
edit: the retain in property is only used if you use the setter, so it will only work if you use the following line:
[self setFlashsets:[listofsetsstring componentsSeparatedByString:#"\n"]];
in you viewDidLoad it should be self.flashsets = this will insure the accessor method is used to set the value, and thus the 'retain' behaviour you specified on the property definition will be implemented.
flashsets = [listofsetsstring componentsSeparatedByString:#"\n"];//it returns autorealesed NsArray.So If you want Longer Use.you should get Owner ship from that array By Alloc or Copy Or Retain.
flashsets = [[listofsetsstring componentsSeparatedByString:#"\n"] retain];
or
flashsets = [[listofsetsstring componentsSeparatedByString:#"\n"]copy];
or
flashsets = [[NsArry alloc ] initWithArray:[listofsetsstring componentsSeparatedByString:#"\n"]];
I don't know if this will help, but you may want to use the setter and getter methods when referring to flashsets - the retain part of the property doesn't apply (I don't think) when setting the variable directly.
Related
I am facing a crashing problem in cellForRowAtIndexPath tableview delegate method
#interface EventListView : UIViewController <UITableViewDelegate, UITableViewDataSource>
IBOutlet UITableView *tblView;
NSMutableArray *arr_EventValues,*arr_Event_Details;
NSMutableArray *arr_EventListDetails;
#property(nonatomic, retain)NSMutableArray *arr_EventValues,*arr_EventListDetails, *arr_Event_Details;
#property(nonatomic, retain)UITableView *tblView;
- (void)viewDidLoad
{
appdelegate = (VibesGuideAppDelegate *)[[UIApplication sharedApplication] delegate];
ViewCalendar = [[CalendarView alloc] initWithNibName:#"CalendarView" bundle:[NSBundle mainBundle]];
[self.navigationController.navigationBar setHidden:YES];
self.arr_Event_Details = [[NSMutableArray alloc] init];
self.arr_EventValues = [[NSMutableArray alloc] init];
[super viewDidLoad];
}
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self.arr_EventListDetails count] > 0)
{
return [self.arr_EventListDetails count];
}
return 0;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
// ------------------------------- Custom cell ------------------------------
Customcell *cell = (Customcell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell = [[[Customcell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.text = #"Hello";
return cell;
}
* -[EventListView tableView:cellForRowAtIndexPath:]: message sent to deallocated instance 0x60e01b0 and I used tableview from xib and set all connections and also got arrayvalues in numberOfRowsInSection in method but in cellForRowAtIndexPath method is not called so please give me idea my issue....
Thanks in advance.
At first it seems your some variable gets released. Make sure you have properly allocated it. If you have declared #property for it you better use the variable as self.variable. You can use retain and in case of IOS 5 strong in property declaration.
Just to be sure you can track if any variable gets released via setting NSZombieEnabled to YES. With zombies enabled, messages to deallocated objects will no longer behave strangely or crash in difficult-to-understand ways, but will instead log a message and die in a predictable and debugger-breakpointable way. You can set NSZombieEnabled by the following steps.
Select Product from the menu bar above. Keep alt/option pressed and select "Test..." or "Run...". Go to the Arguments tab, and add NSZombieEnabled YES in the "Environment Variables" section.
Your tableview itself is already released - the error message says that you send the cellForRowAtIndexPath message to a deallocated instance of the table view - so your problem lies somewhere in not retaining or releasing the EventListView and cannot be seen in the code displayed here.
Check this one:
Table DataSource and delegate is set or not.
Used array in cellForRowAtIndexPath is properly set with property and synthesized as well used with self. name.
First of all you dequeue the cell and then create a new one. This is not a good practice, if you are able to dequeue a cell you should not create a new one. You should have something like this:
Customcell *cell = (Customcell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[[Customcell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
fix this and let me know if you are still running on the same problem.
I know this is an oft-asked question/problem. I've looked through a bunch of Q&A for my problem, but I guess I'm a little thick, because I didn't see an answer anywhere.
I have a file with in an array that I would like to use to populate a tableView.
The problem is that it's not being called. Neither is numberOfRowsInSection or numberOfSectionsInTableView. I far as I can see, only viewDidLoad was called.
I have 1 section, the number of elements in my array equals 3 (as opposed to nil).
Relevant code is here...
- (void)viewDidLoad {
[super viewDidLoad];
FileControl *fileArray = [[FileControl alloc] init];
matArray = [fileArray findUniqueItemsInArray:0 :[fileArray setFileToArray]];
[fileArray release];
NSLog(#"%i \n %#", [matArray count], matArray); // matArray is filled.
NSLog(#"ViewDidLoad"); }
- (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];
}
NSLog(#"CellForRowAtIndexPath");
NSString *text = [matArray objectAtIndex:[indexPath row]];
[[cell textLabel] setText:text];
return cell; }
#interface MaterialTableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView *materialTableView;
NSArray *matArray;
}
#property (nonatomic, retain) NSArray *matArray;
#end
The other methods are standard.
I guess my problem lies in that I don't completely understand the flow well enough.
Any help would be greatly appreciated. Thanks in advance.
Have you set your UIViewController subclass to be the delegate and dataSource of the UITableView in question? Without doing so, none of the methods you mention will be called.
I suppose you are using a UITableViewController.
If you are using UITableView it is a little bit more complicated (in this case you need to implement UITableViewDelegate, UITableViewDataSource protocols).
[update] This is not your case, you are using UITableViewController.
Add this line to the end of your viewDidLoad method:
[self.tableView reloadData];
Or move this:
FileControl *fileArray = [[FileControl alloc] init];
matArray = [fileArray findUniqueItemsInArray:0 :[fileArray setFileToArray]];
[fileArray release];
to the init method. Your init method should look like this:
- (id)initWithStyle:(UITableViewStyle)style {
if ((self = [super initWithStyle:style])) {
FileControl *fileArray = [[FileControl alloc] init];
matArray = [fileArray findUniqueItemsInArray:0 :[fileArray setFileToArray]];
[fileArray release];
NSLog(#"%i \n %#", [matArray count], matArray); // matArray is filled.
NSLog(#"ViewDidLoad");
}
return self;
}
If you do not see any message in the log, it means that you are not using that method to initialize your object.
Please show all your code in the .m and .h files.
I have a suggestion. Just give a shot for a test. In the - (void)viewDidLoad declare this.
instead of : matArray = [fileArray findUniqueItemsInArray:0 :[fileArray setFileToArray]];
Use this: matArray = [[NSArray alloc] initWithArray:[fileArray findUniqueItemsInArray:0 :[fileArray setFileToArray]]];
Did you use
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.matArray count];
}
make sure you have added your tableview delegate to your .h file as shown below.
#interface YourViewController : UIViewController <UITableViewDelegate> {
}
Also make sure that you have connected your datasource and delegate in interface builder.
Do this by doing:
double click on your .xib file so it opens in interface builder.
left click on your tableview just once so its highlighted blue
right click on your tableview now and a menu should pop up.
drag the datasource & delegate to the files owner box.
make sure to save changes while in interface builder.
This should "connect" all the pieces needed to get it to work.
Happy Coding!!
In my app I allow users to add new rows of NSStrings to a UITableView. I save these new strings in an NSMutableArray *dataArray
So for numberOfRowsInSection I return [dataArray count], but it seems to just return 0 all the time so my table is not auto-populating.
If it helps, when I do an NSLog of [dataArray count] as a add more entries, it keeps remaining as 0. Why isn't it increasing?
Any help?
Without looking # your code ,it's not possible to predict the reason..
Then also you can try your HardLuck...below:
First try to NSLog your dataArray to check wether the record is adding in that or not.
It's its ok... you are getting the records.
then you are missing one thing.
reload the table..
[tableView reloadData];
I think this would definitely help you..otherwise put some code over here.
Have you initialised your Array. Here is how I've done it - prob a better way!
.h:
#interface RootViewController : UITableViewController {
NSArray *array;
}
#property (nonatomic, retain) NSArray *array;
#end
.m:
#implementation RootViewController
#synthesize array;
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *mArry = [[NSMutableArray alloc] init];
[mArry addObject:#"An ObecjT"];
self.array = mArry;
[mArry release];
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [array 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];
}
// Configure the cell.
cell.textLabel.text = [array objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSMutableArray *aNewArray = [[NSMutableArray alloc] initWithArray:array];
[aNewArray addObject:#"Your Object"];
self.array = aNewArray;
[aNewArray release];
[self.tableView reloadData];
}
- (void)viewDidUnload {
self.array = nil;
}
- (void)dealloc {
[array release];
[super dealloc];
}
Did you set the delegate for the UITableView in Interface Builder ? please check it.
If you have added, then you have to check with that dataArray whether it is having records or not.
I've subclassed UITableView to create my own data retrieval system, as described in Apple's own Core Data tutorial, but I've hit a problem. The substitute cellForRowAtIndexPath method in my custom table never gets called, not even when I call reloadData or setNeedsDisplay. I've been hunting around for solutions to this one, and it seems that this error can be caused by a multitude of problems. However I've checked all the ones I can find and cannot see anything missing. Can anyone tell me what's likely to be wrong?
P.S. I know the UITableViewDataSource protocol needs to be in triangular brackets, but I couldn't find out how to show triangular brackets on the page without deleting the text between them.
H-File
#interface DataTable : UITableView <UITableViewDataSource> {
NSMutableArray *list;
}
#property (nonatomic, retain) NSMutableArray *list;
#end
M-File
#implementation DataTable
#synthesize list;
-(id) initWithFrame:(CGRect)rect Style:(UITableViewStyle)style{
if (self = [super initWithFrame:rect style:style]){
list = [[NSMutableArray alloc] init];
self.dataSource = self;
}
return self;
}
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [list count];
}
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellID = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil){
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:cellID] autorelease];
}
CH *this = (CH *)[list objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [this.clusterName mutableCopy];
return cell;
}
-(void) dealloc{
[list release];
[super dealloc];
}
#end
Never mind, think I've found it. Basically, you can't set the datasource delegate in that part of the program. Need to do it from its owning view controller.
In the following bit of code, I'm setting the table view cell text with a value from the NSMutableArray 'categories' which is a property of my view controller. That works fine.
But when I try the exact same code in another method, it crashes (it compiles without errors or warnings). If I change the following line in the didSelectRowAtIndexPath method:
NSString *categoryName = [categories objectAtIndex:indexPath.row];
to
NSString *categoryName = [[NSString alloc] initWithString:#"test"];
It works... any ideas?
// 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];
}
// Configure the cell.
NSString *categoryName = [categories objectAtIndex:indexPath.row];
cell.textLabel.text = categoryName;
return cell;
}
// Override to support row selection in the table view.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
printf("User selected row %d\n", [indexPath row] + 1);
ButtonsPageViewController *bView = [ButtonsPageViewController alloc];
NSLog(#"created instance of buttonspageviewcontroller");
NSString *categoryName = [categories objectAtIndex:indexPath.row];
NSLog(#"category name set");
bView.selectedCategory = categoryName;
NSLog(#"selected category property set");
[self.navigationController pushViewController:bView animated:YES];
NSLog(#"push view controller");
[bView release];
}
The difference between
NSString *categoryName = [categories objectAtIndex:indexPath.row];
and
NSString *categoryName = [[NSString alloc] initWithString:#"test"];
Is that the first line copies a pointer to the object (retain count does not change) whereas the second one creates a new object (retain count = 1).
In cellForRowAtIndexPath, when you set the text property, it copies or retains the string, so you're fine. In didSelectRowAtIndexPath you are setting a property of ButtonsPageViewController, which I assume is your own code, but perhaps it is not copying or retaining the object.
Also, the line
ButtonsPageViewController *bView = [ButtonsPageViewController alloc];
is going to lead to problems. You need to call init to properly initialize the object. All you've done in that line is allocate memory for it.
In general, it looks like you need to brush up on Retain/Release memory management. That should save you some trouble.
Like benzado says, it's an issue retaining the selectedCategory value in ButtonsPageViewController.
Are you using #property and #synthesize or are you writing your own accessors? If it's the former, you probably need to look at the property declaration attributes. Otherwise, it's probably a retain/release thing in your custom accessor.
The Declared Properties section of The Objective-C 2.0 Programming Laungauge is a good resource for rules of declaring synthesized accessors.