So I know that if you guys don't like my question you are going to vote me down and reduce my reputation :( but I need to learn and can't find a answer so here I'm risking my reputation again.
Now to the point. All I'm trying to do is one View with two buttons and a table view under the buttons, this table view needs to display a different array depending witch button was click, in other words all I want it to do is if I click button1 display array1, if I click button2 display array2, simple! but I can't get it to work.
Here is a sample of my code:
- (void)viewDidLoad
{
array1 = [[NSArray arrayWithObjects:
#"A",
#"B",
#"c",
#"D", nil] retain];
array2 = [[NSArray arrayWithObjects:
#"1",
#"2",
#"3",
#"4", nil] retain];
}
- (IBAction)btnPeriodicos:(id)sender {
displayArray = 1;
}
- (IBAction)btnRadios:(id)sender {
displayArray = 2;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (displayArray == 1) {
return [array1 count];
}
if (displayArray == 2) {
return [array2 count];
}
[self.tableView reloadData];
}
- (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.textAlignment = UITextAlignmentCenter;
cell.textLabel.textColor = [UIColor blackColor];
if (menuNumberInt == 1) {
cell.textLabel.text = [[periodicoArray objectAtIndex:indexPath.row] retain];
}
if (menuNumberInt == 2) {
cell.textLabel.text = [[radioArray objectAtIndex:indexPath.row] retain];
}
return cell;
}
If I put instead of the if else statements either [array1 count] for the numberOfRowsInSection and the cell.textLabel.text = [[periodicoArray objectAtIndex:indexPath.row] retain]; the app loads with the table fill with that array so I guess the table works, but how can I make my buttons change the table cells?
any help is greatly appreciated.
Thanks
You can have an iVar variable for NSArray *currentArray. In viewDidLoad you can define your two arrays (as you currently do) but then assign currentArray to array1.
Then, change all the tableView callbacks to operate off of currentArray and get rid of the if (displayArray == x) checks.
in the (IBAction) button handlers, assign currentArray to the appropriate array and call [tableView reloadData]. that will clear the table and trigger all the tableView callbacks to happen again. since the currentArray changed, all the callback will pull data from the appropriate array.
Hope that helps.
Related
I'm trying to create an iOS app in which I must have a UITableView that every time I press a new entry button, a newcell appears with the time when I pressed that button. My problem is that everytime I press the buttons, not only the cell which is created displays the current time, but the cells above it, which were showing a different time, reload and also show the current time. To try and explain it better, if I press the button at 8:05, 9:01 and 9:10, i want the UITableView to show:
-8:05
-9:01
-9:10
Instead, it's showing:
-9:10
-9:10
-9:10.
What do I do?? Thanks
Here's my code ( newEntry is the button and brain is an object where I have the method to get the current time)
#implementation MarcaPontoViewController{
NSMutableArray *_entryArray;
#synthesize brain=_brain;
- (void)viewDidLoad
{
[super viewDidLoad];
_brain = [[Brain alloc] init];
_entryArray = [[NSMutableArray alloc] init];
//[self updateTime];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [_entryArray count];
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier= #"myCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [_entryArray lastObject];
}
return cell;
}
- (IBAction)newEntry:(id)sender {
[_entryArray addObject:[self.brain currentTime]];
[_timeTable reloadData];
}
#end
Your problem is here in this line :
cell.textLabel.text = [_entryArray lastObject];
You need to use :
cell.textLabel.text = [_entryArray objectAtIndex:indexPath.row];
Or,
cell.textLabel.text = _entryArray[indexPath.row];
[_entryArray lastObject] always gives the last returned object.
Use
cell.textLabel.text = [_entryArray objectAtIndex: indexPath.row];
The line cell.textLabel.text = [_entryArray lastObject] will only ever return the last object in the array, which is why you are seeing the same time repeated. Change this to:
// in cellForRowAtIndexPath:
cell.textLabel.text = [_entryArray objectAtIndex:indexPath.row];
This should fix the underlying problem.
I have an app consisting of a TabBar with a few TabBarControllers. One Controller contains a very simple table, which is supposed to display the contents of a NSMutableDictionary. When you hit the appropriate button, the Dictionary is updated in a separate Controller and the view switches to the UITableViewController, displaying the newly updated table.
I can see the Dictionary being updated. But the TableView never reflects the changes. In fact, it seems to display the changes only the 1st time I enter that screen.
I have tried [self table.reloadData] and while it gets called, the changes aren't reflected to the UITableView.
Does anyone have any suggestions? I am happy to post code, but am unsure what to post.
Update: the table is updated and refreshed properly only the 1st time it is displayed. Subsequent displays simply show the original contents.
Background:
The tableview gets filled from a dictionary: appDelegate.currentFave. The tableview should get refreshed each time the ViewController is invoked by the TabBarController.
- (void)viewWillAppear:(BOOL)animated
{
NSLog(#"in viewWillAppear");
[super viewWillAppear:animated];
[self loadFavesFile];
[self.tableView reloadData];
}
// load the Favorites file from disk
- (void) loadFavesFile
{
// get location of file
NSString *path = [self getFavesFilePath];
// The Favorites .plist data is different from the Affirmations in that it will never be stored in the bundle. Instead,
// if it exists, then use it. If not, no problem.
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
// read Faves file and store it for later use...
NSMutableDictionary *tempDict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
appDelegate.sharedData.dictFaves = tempDict;
// grab the latest quote. Append it to the list of existing favorites
NSString *key = [NSString stringWithFormat:#"%d", appDelegate.sharedData.dictFaves.count + 1];
NSString *newFave = [NSString stringWithFormat:#"%#", appDelegate.currentFave];
[appDelegate.sharedData.dictFaves setObject:newFave forKey:key];
} else {
NSLog(#"Favorites file doesn't exist");
appDelegate.sharedData.dictFaves = nil;
}
}
// this gets invoked the very first call. Only once per running of the App.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// reuse or create the cell
static NSString *cellID = #"cellId";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
// allow longer lines to wrap
cell.textLabel.numberOfLines = 0; // Multiline
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.font = [UIFont fontWithName:#"Chalkduster" size:(16)];
cell.textLabel.textColor = [UIColor yellowColor];
// NOTE: for reasons unknown, I cannot set either the cell- or table- background color. So it must be done using the Label.
// set the text for the cell
NSString *row = [NSString stringWithFormat:#"%d", indexPath.row + 1];
cell.textLabel.text = [appDelegate.sharedData.dictFaves objectForKey:row];
return cell;
}
I found the problem. I was not properly initializing and assignng the TableView in my view controller. See below
- (void)viewDidLoad
{
[super viewDidLoad];
tableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
tableView.dataSource = self;
tableView.delegate = self;
tableView.backgroundColor=[UIColor blackColor];
self.view = tableView;
}
Assuming the code you have put up is correct, you want to use [self.table reloadData]. You have the . in the wrong place.
I had this same problem yesterday, for me it turned out I had set the wrong file owner in interface builder and hadn't set up the data source and delegates for the table view properly.
Try going into interface builder and right-clicking on the file owner, this should show you if anything isn't connected up properly.
You should make sure that your Interface Builder connections are set up properly, but what this problem really sounds like is that you have your UITableViewCell setup code in cellForRowAtIndexPath: inside your if(cell == nil) statement. Which it shouldn't be. Let me explain. If you have a list of cells, and you want to set the titles to each cell to a string in an array called myArray, right now your (incorrect) code looks like this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cellIdentifier"] autorelease];
[[cell textLabel] setText:[myArray objectAtIndex:[indexPath row]]];
}
return cell;
}
Can you see the problem with that logic? The cell will only get an updated title if no reusable cell can be found, which, in your case, sounds like the situation. Apple says that you should create a 'new' cell each time cellForRowAtIndexPath: is called, which means that you put all of your setup code outside of the if(cell == nil) check.
Continuing with this example, the proper code would look like this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cellIdentifier"] autorelease];
}
[[cell textLabel] setText:[myArray objectAtIndex:[indexPath row]]];
return cell;
}
This way, the cell gets assigned the proper string whether or not a reusable cell is found and so calling reloadData will have the desired effect.
I am trying to store a grouped UITableView in an array (eg all the individual cells) so that i can retain which cells the user has tapped (and add the check accessory to it). Every time i try and restore the cells, i end up with the most recent cells to have been displayed (ie. the cells that have just appeared at the bottom of the screen appear at the top when scrolling back up.
i cant figure out hot to do this correctly so any help is very welcome
thanks
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyManager *dataStore = (MyManager* )[MyManager sharedManager];
NSNumber *dif = [[NSNumber alloc] initWithInt:-1];
if (indexPath.section == 0) {
dif = [NSNumber numberWithInt:0];
} else if (indexPath.section == 1) {
dif = [NSNumber numberWithInt:3];
} else if (indexPath.section == 2) {
dif = [NSNumber numberWithInt:5];
} else if (indexPath.section == 3) {
dif = [NSNumber numberWithInt:9];
}
if ([dataStore.masterArray objectAtIndex:(indexPath.row+[dif intValue])]==#"0") {
//array is initalised with 16 strings of #"0", just to fill it
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
NSArray *listData =[self.data objectForKey:
[self.sortedKeys objectAtIndex:[indexPath section]]];
UITableViewCell * cell = [tableView
dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
if(cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:SimpleTableIdentifier] autorelease];
}
NSUInteger Row = [indexPath row];
cell.textLabel.text = [listData objectAtIndex:Row];
cell.accessoryType = UITableViewCellAccessoryNone;
[dataStore.masterArray replaceObjectAtIndex:(indexPath.row + [dif intValue]) withObject:cell];
cell.textLabel.text = [listData objectAtIndex:Row];
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
}
else {
UITableViewCell *cell = [dataStore.masterArray objectAtIndex:(indexPath.row+[dif intValue])];
return cell;
}
}
i would assume that this code should check to see if there is a cell at the index, if no then make and display one (this works fine). If the cell does exist, pull it out of the array an display it.
The problem is that cells are not all created at once. They are created and destroyed when necessary. If the cells go out of view, they may be destroyed to save memory. Instead of storing the cells themselves in an array, store a boolean value in an array. Then when the cell is created for a specific row, use the bool value out of the array to determine if it should be checked.
I can't display array in UITableView. The thing I do is - in viewWILLappear I'm creating array. In viewDIDappear I'm filling the array. But when I run [myArr count] or [myArr objectAtIndex:indexPath.row] in table setup I get empty table. If I define constant integer as row count and some constant string as cell text everything works fine. Is there some populate() method I have to run or is it a problem with some order of declarations?
Thanks for any help. Here's the code:
- (void)viewWillAppear:(BOOL)animated {
myArr = [[NSMutableArray alloc] initWithCapacity:100];
}
- (void)viewDidAppear:(BOOL)animated {
[self load_array];
}
- (void) load_array {
for (SomeObject *someObject in SomeObjects) {
[myArr addObject:someObject.someString];
NSLog(#"Value: %#", [myArr objectAtIndex:([myArr count]-1)]); // works
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [myArr count]; // works if I return const ("return 2")
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (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];
}
cell.textLabel.text = [myArr objectAtIndex:indexPath.row]; //=#"ASDF" works.
return cell;
}
You need to perform reloadData on your table view to make the view re-load the table cells.
Update: You should not allocate your array in the viewWillAppear, as this method might be called several times. Construct the array in the viewDidload: and fill it there, or in a background thread, or in the viewWillAppear: (using a conditional statement to check if its already filled). You should also make sure that you do not create a memory leak, from the code you provided it is likely that myArr will be replaced by a newly allocated array without being released.
I have retrieved data from Json URL and displayed it in a table view. I have also inlcuced a button in table view. On clicking the button the data must be transferred to a another table view. The problem is that i could send the data to a view and could display it on a label. But i couldnt bind the dat to table view ... Here's some of the code snippets...
Buy Button...
-(IBAction)Buybutton{
Product *selectedProduct = [[data products]objectAtIndex:0];
CartViewController *cartviewcontroller = [[[CartViewController alloc] initWithNibName:#"CartViewController" bundle:nil]autorelease];
cartviewcontroller.product= selectedProduct;
[self.view addSubview:cartviewcontroller.view];
}
CartView...
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
data = [GlobalData SharedData];
NSMutableArray *prod =[[NSMutableArray alloc]init];
prod = [data products];
for(NSDictionary *product in prod){
Cart *myprod = [[Cart alloc]init];
myprod.Description = [product Description];
myprod.ProductImage =[product ProductImage];
myprod.ProductName = [product ProductName];
myprod.SalePrice = [product SalePrice];
[data.carts addObject:myprod];
[myprod release];
}
Cart *cart = [[data carts]objectAtIndex:0];
NSString *productname=[cart ProductName];
self.label.text =productname;
NSLog(#"carts");
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [data.carts count];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 75;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"cellforrow");
static NSString *CellIdentifier = #"Cell";
ProductCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell ==nil)
{
cell = [[[ProductCell alloc]initWithFrame:CGRectZero reuseIdentifier:CellIdentifier]autorelease];
}
NSUInteger row = [indexPath row];
Cart *cart = [[data carts]objectAtIndex:row];
cell.productNameLabel.text = [cart ProductName];
return cell;
}
I am also getting the following error in the console
2010-06-11 18:34:29.169 navigation[4109:207] *** -[CartViewController tableView:numberOfRowsInSection:]: message sent to deallocated instance 0xcb4d4f90
Your view controller is autoreleased that's why you have the error in the console.
CartViewController *cartviewcontroller =
[[[CartViewController alloc]
initWithNibName:#"CartViewController"
bundle:nil] ***autorelease***];
You should store your view controller in a member variable.
This is depreciated:
cell = [[[ProductCell alloc]initWithFrame:CGRectZero reuseIdentifier:CellIdentifier]autorelease];
Use initWithStyle:reuseIdentifier: instead.
Autorelease isn't a convenience function. It has a specific use. You're only supposed to use it when you are immediately handing an object off to an another external object. Don't use autorelease unless the sending object longer cares if the receiving object lives or dies.
A good rule of thumb is if you ever refer to the receiving object again in the sending object, don't autorelease the receiving object.