I have implemented "Add to Favourites" functionality for my iPhone application. It works fine except adding cells into my Favourite Table View during runtime. For example, I have given following methods.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
tableView.hidden = YES;
warningLabel.hidden = YES;
// Load any change in favourites
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:kFavouriteItemsKey];
self.favourites = [NSKeyedUnarchiver unarchiveObjectWithData:data];
if([self.favourites count] > 0)
tableView.hidden = NO;
else
warningLabel.hidden = NO;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.favourites count]; // Favorites is a dictionary contains required data
}
- (UITableViewCell *)tableView:(UITableView *)tView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [NSString stringWithFormat:#"index: %d",indexPath.row];
return cell;
}
This code works fine and display rows correctly for the first time only! After tableview is loaded and if I add new item(s) in favorites or delete any item(s), it doesn't make any difference to my tableview! I want to display exactly what is available in Favourites dictionary. It seems CellForRowAtIndexPath doesn't get invoked when ViewAppear again. Is there any method for TableView that I can use to achieve my requirements?
I think you've missed to call [tableView reloadData];
The very easy way is to just call [tableView reloadData] whenever you make any changes.
There is also a better (faster for large tables, and possibly animated; more elegant), but much more complicated way which I won't go into unless you decide the reloadData way isn't sufficient for you.
Related
I have a custom/sub-classed UITableViewCell using NSLayoutConstraints. The left most UIImageView may or may not be populated with an image, and if not, the objects to right of this field will naturally shift to the left. Works well within the custom UITableViewCell, however I'll be populating the content with my custom UITableViewController. Unfortunately, following code will populate every row cell.dispatchedView with an image -- though I've trapped to not populate rows with anything.
This has something to do with the dequeueReusableCellWithIdentifier. Ideas?
static NSString *CellIdentifier = #"CellIdentifier";
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[NXGActiveUnitsCell class] forCellReuseIdentifier:CellIdentifier];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
NSDictionary *item = [self.model.dataSource objectAtIndex:indexPath.row];
NXGActiveUnitsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if([[[item objectForKey:#"cfs_no"] clean] length] > 0) {
cell.dispatchedView.image = [UIImage imageNamed:#"p.png"];
NSLog(#">>>%#",[item objectForKey:#"cfs_no"] );
} else {
NSLog(#">>> i got nothing so I should not touch this row...");
}
cell.departmentIconView.image = [UIImage imageNamed:#"f.png"];
cell.unitLabel.text = [item valueForKey:#"unit_id"];
return cell;
}
I don't know if this already solves your problem, but you should
definitely set
cell.dispatchedView.image = nil;
in the else-case, because cells are reused.
I am trying to make a ToDo list app and I can't for the life of me seem to figure out how to make the text box's typed text go into a box with a tick box for me to be able to change to completed.
Can anyone help me? I am just getting started in Xcode so please explain why/how it works that way I can learn for the future. Thanks guys!
App Rendering (What I am trying to make)
http://imgur.com/wcNXu0z
Currently in Xcode (What I have so far)
http://imgur.com/PLUVaVg
You need to create an IBAction for add button. So its get called when you click the button and store the entered text in UItextfield in an array and you will use that array to add rows in your table.
For example consider the code :
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [dataArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
[cell.textLabel setText: [dataArray objectAtIndex:indexPath.row];
return cell;
}
-(IBAction)addCity:(id)sender
{
[tableView beginUpdates];
[dataArray addObject:#"City"];
NSArray *paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:[dataArray count]-1 inSection:1]];
[[self tableView] insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationTop];
[tableView endUpdates];
}
I'd strongly recommend you check out the free Sensible TableView framework. The framework should help you automatically create your text fields and automatically fill/save their data.
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 can successfuly delete data from tableview , but when i go to main menu and come back then i see all the old data,
how to make data consistent , i.e once deleted it will be gone forever
- (void)viewDidLoad
{
[super viewDidLoad];
appDelegate = (DatabaseTestAppDelegate *)[[UIApplication sharedApplication] delegate];
{
appDelegate.favDetail = [[NSMutableArray alloc] initWithObjects:#"1", #"2",#"4",nil];
}
}
- (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];
}
appDelegate = (DatabaseTestAppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *cc=[appDelegate.favDetail objectAtIndex:indexPath.row];
NSLog(#" vale is %d",indexPath.row);
// Configure the cell...
NSArray *theParameters = [cc componentsSeparatedByString:#","];
NSLog(#"array is %#",cc);
NSLog(#"arraytheParameters is %#",theParameters);
cell.text=cc;//theParameters;
return cell;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{ NSLog(#"matrix is her%#",appDelegate.favDetail);
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[appDelegate.favDetail removeObjectAtIndex: indexPath.row];
[tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject: indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
/*
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
} */
}
- (void)viewWillAppear:(BOOL)animated
{ [tableView reloadData];
[super viewWillAppear:animated]; // no use , it shows old data
}
thanks
If you are looking to save the state of your model beyond the life of your table view controller, there are few things you can do. One is to write the array to a file in the documents directory and read it back on reload. This would work well will small sets of data. But if you are going to use a large data set, you have to use Core Data.
As for this specific case, you are reinitializing the data on every viewDidLoad. I suggest you do this in viewDidLoad –
...
if ( appDelegate.favDetail == nil ) {
appDelegate.favDetail = [[NSMutableArray alloc] initWithObjects:#"1", #"2",#"4",nil];
}
...
This will make sure that you don't reinitialize it.
you have to delete the data in both your view and your model
Check out the place where appDelegate.favDetail is getting data from...
While deleting you are removing from appDelegate.favDetail but When you go to main menu and come back you are reassigning the values to appDelegate.favDetail...
Checkout that appDelegate.favDetail only gets the value once.. or another option is you remove the data from the main source from where the favDetail gets the value
Happy iCoding....
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.