UITableView with NSMutableArray - iphone

I’m populating a UITableView based on the values of an NSMutableArray. This table view has search results. If the user clicks in one of the results, one will navigate to another screen. If the user clicks “back”, the search results are filled in again. At this point, while the table view is being repopulated, the old values still appear, just as I want. However, since I’m doing:
- (void)viewWillAppear:(BOOL)animated
{
NSMutableArray *m = [[NSMutableArray alloc] init];
self.searchResultsArray = m;
[m release];
}
The old cells information is no longer available. Thus, the app crashes if the user clicks in one of the old cells or scrolls the UITableView because I’m accessing the mutable array which was reinitialized above.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *cellArray = [searchResultsArray objectAtIndex:indexPath.row];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
appDelegate.selectedCell = [searchResultsArray objectAtIndex:indexPath.row];
}
Do you have any suggestions concerning how should I do this properly?
Thanks.

this is because you are re-initalizing the array each time the view comes back in focus, the array will then have 0 objects in, causing the issue when you select a row and reference an index in the array that simply was wiped when the viewWillAppear is called.
why not init ' self.searchResultsArray ' in viewDidLoad (remembering to undo this with release when the device receives memory warning)
let me know how you get on.

You should reset the array only when the view loads:
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *m = [[[NSMutableArray alloc] init] mutableCopy];
self.searchResultsArray = m;
[m release];
}
You should always call the reloadData: method when changing the data in the UITableViewDataSourceDelegate instance.
Let me know if this helps

Please try below code:
- (void)viewWillAppear:(BOOL)animated
{
// Your search result array with your old values
// Now add or appened new data to your old search results.
[self.searchResultsArray addObject:#"Your Value 1"];
[self.searchResultsArray addObject:#"Your Value 2"];
[self.searchResultsArray addObject:#"Your Value 3"];
[self.tableView reloadData];
// if you need to add new values from a array put this code in a loop.
}
It should helps you...
Thx

It seems to me that you are not initialising the NSArray in the right method (viewDidLoad:).
Using XLData you don't have to care about where you set up the storage, reload the UITableView or add items to the NSArray (searchResultsArray) since it keeps track of the data (NSArray) and updates the UITableView accordingly and on the fly.

Related

UITableView in Storyboard appears empty

It's my first time using Storyboard to build an app. I'm trying to create a UITableView with a custom cell. I've created the cell in IB and created a custom tableViewCell class for it (added some labels, created appropriate outlets, connected them in IB and assigned the custom class to the custom cell in IB).
In the ViewController responsible for the TableView I create the data source (a dict with some arrays) and fill out all the obligatory methods (I've tried both with UITableViewControler and with a UIViewController that is set as a delegate and data source for the tableview)
And when I run the app - the tableview is empty. And after doing some NSLogging I've noticed that the data source methods are never executed. And I have NO IDEA why.
I'm going crazy about this for a few hours now. Please help me out :)
Let me know if you need to see the code or Storyboard, or whatever else.
UPDATE: Alright, after some digging, I've decided to test out the same code but using an NSMutableArray as data source instead of a NSMutableDictionary. And it works!
Now, could someone explain to me why it didn't work with a dict?
Here's what did. I had a dict with 5 arrays, and each array had 5 strings.
In the numberOfRowsForSection method, I returned [dict count]
And in the cellForRowAtIndexPath method, I've used this code
NSArray * routeArray = [dealsDict objectForKey:#"route"];
cell.routeName.text = [routeArray objectAtIndex:indexPath.row];
NSArray * companyArray = [dealsDict objectForKey:#"company"];
cell.companyName.text = [companyArray objectAtIndex:indexPath.row];
NSArray * priceArray = [dealsDict objectForKey:#"price"];
cell.priceLabel.text = [priceArray objectAtIndex:indexPath.row];
NSArray * dateArray = [dealsDict objectForKey:#"date"];
cell.dateLabel.text = [dateArray objectAtIndex:indexPath.row];
NSArray * monthArray = [dealsDict objectForKey:#"month"];
cell.monthLabel.text = [monthArray objectAtIndex:indexPath.row];
NSLog(#"I'm in here");
return cell;
why didn't it want to show anything?
In the IB, select your table view, and make sure that the delegate and dataSource outlets are set for your controller
UITableView need some collection dataset as data source. Its delegate method "cellForRowAtIndexPath" get called equals to number of elements of collection (ARRAY). like numberOfRowsInSection delegate tells the table view that it need to call cellForRowAtIndexPath for every element in collection. and it also need some iterator to read each time the next element, in case of dictionary it always stick to same data element at each call of cellForRowAtIndexPath. I hope it wil give you the idea of its working, Please let me know if you need anything else to know.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.data count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MessagesCell *cell = [tableView dequeueReusableCellWithIdentifier:#"messageCellIdentifier"];
Message *msg = [self.data objectAtIndex:indexPath.row];
cell.Name.text = msg.Name;
cell.Message.text = msg.MessageText;
cell.Time.text = msg.Time;
return cell;
}

NSMutableArray doesn't populate tableView

I have few table view controllers and I want selections from them to be shown on "ResultTableViewController". I also have array that collects the selected data and when i finally push it to the "ResultViewController" it shows only the last selection. Please help
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
firstarr = [[NSMutableArray alloc]init]; //array with questions
[self.firstarr addObject:[self.data objectAtIndex:indexPath.row]]; //collects the data properly
BodyDetailViewController* vc =[[BodyDetailViewController alloc] initWithNibName:#"BodyDetailViewController" bundle:nil];
vc.someArray = firstarr; //some array - ViewController with Results.
[self.navigationController pushViewController:vc animated:YES];
}
You have to remove this line :
firstarr = [[NSMutableArray alloc]init];
Because you're initializing your NSMutableArray each time you're selecting a cell, so all the data previously stored is erased and vc.someArray is getting an array with only your last selection, that's why ;)
Init your NSMutableArray outside the method, in your viewDidLoad for example
This...
firstarr = [[NSMutableArray alloc]init]; //array with questions
...creates a new array. Whatever was in firstarr previously is gone when you do a new selection.
Either create the array once somewhere else (when the object is initialized?) or append its content to vc.someArray instead of replacing it.

Array nil (even when addObject:) [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
addObject: to array not working (array still nil)
EVERYTHING UPDATED
This app is a table view with a tab bar controller. I am logging the count of the array: arrayOfFavourites and even though i add an object is continues to have a nil value, my relating code, all objects shown are allocated and initialized in the code (previous or present) some are instances and some are properties:
ListViewController.m:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"TOUCHED CELL!");
// Push the web view controller onto the navigation stack - this implicitly
// creates the web view controller's view the first time through
[[self navigationController] pushViewController:webViewController animated:YES];
// Grab the selected item
entry = [[channel items] objectAtIndex:[indexPath row]];
if (!entry) {
NSLog(#"!entry");
}
// Construct a URL with the link string of the item
NSURL *url = [NSURL URLWithString:[entry link]];
// Construct a request object with that URL
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Load the request into the web view
[[webViewController webView] loadRequest:req];
// Take the cell we pressed
// IMPORTANT PART
CELL = [tableView cellForRowAtIndexPath:indexPath];
[webViewController setItem:entry];
webViewController = nil;
webViewController = [[WebViewController alloc] init];
[entry release];
}
WebViewController.m:
You shake to favorite a cell
-(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
cellToPassOn = nil;
NSLog(#"Favouriting"); // YES I KNOW SPELLING
// This is pretty simple, what we do is we take the cell we touched and take its title and link
// then put it inside an array in the Favourites class
Favourites *fav = [[Favourites alloc] init];
ListViewController *list = [[ListViewController alloc] init];
[self setCellToPassOn: [list CELL]];
if (!item) {
NSLog(#"NILLED ITEM");
}
[[fav arrayOfFavourites] addObject:[item autorelease]];
[fav setCell: cellToPassOn];
}
Favourites.m:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"ROWS NO.");
NSLog(#"%i", [arrayOfFavourites count]);
return [arrayOfFavourites count];
}
Favourites:
A CLASS, ON TAB BAR CONTROLLER
WEBVIEWCONROLLER:
CONTROLLER FOR DIFFERENT WEB VIEWS
LISTVIEWCONTROLLER:
DATA PROVIDER
Actually what happens is when i shake i reload the table view data and i add an object to an array (array of favorites) the count is one.... GOOD! But then when i shake again (in a different article, my app has different webViews when i press different cells.) It is still 1... weird.... if i go to favorites class that array remains one.. ok... so as you can see i am returning the arrayOfFavourites count to numberOfRowsInSection (which is 1) but no cells appear and the cellForRowAtIndexPath is never called (using an NSLOG) why is this happening I AM VERY ANNOYED!
In your Favourites.m numberOfRowsInSection function, looks like you should do this:
if(arrayOfFavourites == NULL)
{
arrayOfFavourites = [[NSMutableArray alloc] init];
}
Because you're reinitializing (and likely leaking) in every single call to numberOfRowsInSection (which gets called each time the table needs to know how many rows it must display -- i.e. very often).
You create and destroy a new Favourites object every time you go through -motionBegan:withEvent:, and you create a new array every time you go through -tableView:numberOfRowsInSection:. If you want data to persist beyond those events, you need to keep the objects around.
Let review this part of your code :
-(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
cellToPassOn = nil;
NSLog(#"Favouriting"); // YES I KNOW SPELLING
// This is pretty simple, what we do is we take the cell we touched and take its title and link
// then put it inside an array in the Favourites class
// HERE you are creating a NEW fav
Favourites *fav = [[Favourites alloc] init];
// HERE you are creating a NEW list
ListViewController *list = [[ListViewController alloc] init];
// SO HERE what is "CELL" doing, returning some constant or static object?
[self setCellToPassOn: [list CELL]];
// HERE what is item and where does it come from
if (!item) {
NSLog(#"NILLED ITEM");
}
// Here you take an array of an object you just created and autoreleasing the item
// this is not the regular way to handle memory management in Cocoa,
// depending on what you are doing to item else where you could get item == deallocated pretty soon
[[fav arrayOfFavourites] addObject:[item autorelease]];
[fav setCell: cellToPassOn];
HERE you are releasing fav
[fav release];
HERE fav don't exist anymore as well as the array to which you've added something to it.
[list release];
item = nil;
}
Unless I'm reading your code incorrectly I have the feeling that you are trying to have some persistence with "volatile" object.
You need to make a #property for those object to survive longer that one method call.
Every time you create a new object it's new and have no knowledge of the precedent one.
And if we look at this code :
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// HERE everytime the tableview is asking for the numberOfRowsInSection, you create a new array
// And that new empty array is replacing your old one.
// That is your "weird" thing, it's doing what you are asking it to do, set it back to a new empty array.
arrayOfFavourites = [[NSMutableArray alloc] init];
NSLog(#"ROWS NO.");
NSLog(#"%i", [arrayOfFavourites count]);
return [arrayOfFavourites count];
}

Why does reordering my tableView mess up my data?

I have two different table views in which I use the exact same code in tableView:MoveRowAtIndexPath:ToIndexPath: to support user reordering of the rows. One of these tableViews works perfectly. The other one, however, gets confused and starts displaying the same subview no matter which row is selected - i.e. its row indexing seems to have got messed up.
I've temporarily fixed this by adding a [tableView reloadData] at the end of theMoveRowAtIndexPath method, but I don't understand why it wasn't working in the first place - especially since another view with the exact same code works perfectly. Obviously, there must be another method in this view controller which is messing it up, but I don't know where to look.
Here is the code that is the same in both:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
userDrivenDataModelChange = YES;
NSMutableArray *things = [[fetchedResultsController fetchedObjects] mutableCopy];
NSManagedObject *thing = [[self fetchedResultsController] objectAtIndexPath:fromIndexPath];
[things removeObject:thing];
[things insertObject:thing atIndex:[toIndexPath row]];
int i = 0;
for (NSManagedObject *mo in things)
{
[mo setValue:[NSNumber numberWithInt:i++] forKey:#"displayOrder"];
}
[things release], things = nil;
[managedObjectContext save:nil];
userDrivenDataModelChange = NO;
}
(For what it's worth, the one that works is the child view of the one that doesn't, and they are in a to-many Core Data relationship).
Use a different identifier for each tableviews in
(UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier
If you use the same identifier string, they will pickup each other's cached cell objects and show inconsistent data.
I forgot that I was using a custom cell on the parent view, and that the user presses a UIButton within the cell, rather than the cell itself. The custom cell has its index path set as a property by tableView:cellForRowAtIndexPath:, which of course never gets called again after the table cells are moved. Hence, I had to add a [tableView reloadData] to make sure the cells get updated.

UITable crashing when same row is selected twice

I have a UITableView, and when didSelectRowAtIndexPath is called on a row, it switches perfectly to the next view. However, when I click the 'back' buttton and then select the same row previously selected...my app crashes. It does not crash if I select a different row. Here's the code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *tempEventDictionary = [[NSDictionary alloc]initWithDictionary:[arrayWithEvents objectAtIndex:indexPath.row]];
NSLog(#"%i",tempEventDictionary);
//push to new view and set myArray in the cardPage
CardPageViewController *cardPageViewController = [[CardPageViewController alloc] init];
cardPageViewController.eventDictionary = tempEventDictionary;
[self presentModalViewController:cardPageViewController animated:YES];
[cardPageViewController release];
[tempEventDictionary release];
}
Crashes with “EXC_BAD_ACCESS” message.
As you can see, I am printing the pointer address of the NSDictionary, and it seems to be looking for the same address for each individual indexPath.row. This means that the pointer location is being released, and when I try to reasign it to a value of the same indexPath.row, the old pointer address is being searched for, yet it does not exist. Maybe I'm totally wrong here. Any help is appreciated.
There's nothing obviously wrong with the code you've posted. My guess would be that you're overreleasing one of your data objects somewhere within CardPageViewController and then when your code tries to make a temporary dictionary from the same data again, it encounters a dealloced object within the dictionary and that's when the crash happens.
I have a "hack" of an answer that keeps the object alive before the retain count goes all the way down with this elusive autorelease. I initialize the dictionary, and then set it so the retain count goes to 2, and the hidden (to my eyes) autorelease doesn't crash the program. Here is the code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//---send data to cardPage
CardPageViewController *cardPageViewController = [CardPageViewController alloc];
NSDictionary *tempEventDictionary = [[NSDictionary alloc]initWithDictionary:[arrayWithEvents objectAtIndex:indexPath.row]];
cardPageViewController.eventDictionary = [arrayWithEvents objectAtIndex:indexPath.row];
[self presentModalViewController:cardPageViewController animated:YES];
[cardPageViewController release];
}
I hope this helps someone who can't find this released dictionary.
Why not create a custom init that takes a dictionary and then copy the dictionary inside the your custom init for the new view controller?