How to Create UITableView with History of Button Clicks - xcode

I'm creating an app that should list the date and time when a button is clicked and put the list inside a UITableView. My idea is to get the date and timestamp every time the user taps the button and then save it in an array of dictionary objects of every time and date when the button was clicked. I'll also have another button that simply loads a modal view that displays the said UITableView with the list of the history of button clicks.
I was able to do it partially with my table getting populated with the number of dictionary entries inside the array. Problem is, it always end up with the same time and date for all of the entries.
Here's a screenshot of the table initially with one entry.
and this what happens when I tapped the button many times. It displays the updated time for all rows.
How can I display the history in the table and prevent it from being updated? I'm simply using NSUserDefaults also in saving the data.
Here's some code in my Button Clicked method:
- (IBAction)btnClicked:(id)sender
{
NSLog(#"Button pressed");
// Gets the current time and formats it
NSDate *timeNow = [NSDate date];
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
[timeFormatter setDateFormat:#"HH:mm a"];
// Gets the current date and formats it
NSDate *dateNow = [[NSDate alloc] init];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MMM dd, yyyy"];
NSString *currentTime = [timeFormatter stringFromDate:timeNow];
NSString *currentDate = [dateFormatter stringFromDate:dateNow];
NSString *timestamp = currentTime;
NSString *date = currentDate;
// This is where values gets saved
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:timestamp forKey:#"TimeStamp"];
[defaults setObject:date forKey:#"Date"];
[defaults synchronize];
NSString *time = [defaults objectForKey:#"TimeStamp"];
NSString *dateToday = [defaults objectForKey:#"Date"];
tableVC.tableDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:time, #"Time", dateToday, #"Date", nil];
[tableVC.tableArray addObject:tableVC.tableDict];
[tableVC.table reloadData];
}
This is my viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *time = [defaults objectForKey:kTimeStampText];
NSString *date = [defaults objectForKey:kDateText];
tableDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:time, #"Time", date, #"Date", nil];
tableArray = [[NSMutableArray alloc] initWithObjects:tableDict, nil];
}
This is my table methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *customCell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:#"CustomCell"];
if (customCell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell"
owner:self
options:nil];
for (id oneObject in nib) if ([oneObject isKindOfClass:[CustomCell class]])
customCell = (CustomCell *)oneObject;
}
customCell.dateLbl.text = [tableDict objectForKey:#"Date"];
customCell.timeLbl.text = [tableDict objectForKey:#"Time"];
return customCell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 74;
}

Ok I think I found your problem, you are accessing the same date for each table row.
customCell.dateLbl.text = [tableDict objectForKey:#"Date"];
customCell.timeLbl.text = [tableDict objectForKey:#"Time"];
Is incorrect
NSDictionarry *dict = [tableArray objectAtIndex:[indexPath row]];
customCell.dateLbl.text = [dict objectForKey:#"Date"];
customCell.timeLbl.text = [dict objectForKey:#"Time"];
Now that should loop through it nicely and print all dates.
The problem with the code you had was that the row for index path method gets called for each row in the tableview, ie it is like a loop, so you assign each cells properties on it's own, hope this makes sense.

Related

XCode, table view cellForRowAtIndexPath

I know there is a simple solution to this but I can't seem to be able to tell :/
cell.textLabel.text = [BooksBorrowed objectAtIndex:0];
I have that in my cellForRowAtIndexPath method, bookName is a string.
It crashes and leaves no error in log. I dont know what I am doing wrong.
bookName is a string that i get from JSON Parsing and has content.
(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(#"Book Name is %#", BooksBorrowed[0]);
cell.textLabel.text = [BooksBorrowed objectAtIndex:0];
return cell;
}
This is how I get the BooksBorrowed array:
- (void)updateMyBooks
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Fetch data on a background thread:
NSString *authFormatString =
#"http://localhost:8888/Jineel_lib/bookBorrowed.php?uid=%d";
NSString *urlString = [NSString stringWithFormat:authFormatString, 1];
NSURL *url = [NSURL URLWithString:urlString];
NSString *contents = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
response1 = [contents JSONValue];
if (contents) {
NSMutableArray *newBooksBorrowed = [NSMutableArray array];
// ... Parse JSON response and add objects to newBooksBorrowed ...
BookName = [[NSString alloc]init];
DateBorrowed = [[NSString alloc]init];
BookID = [[NSString alloc]init];
BookExtended = [[NSString alloc]init];
BookReturned = [[NSString alloc]init];
BookName = [response1 valueForKey:#"BookName"];
BookID = [response1 valueForKey:#"BookID"];
DateBorrowed = [response1 valueForKey:#"DateBorrowed"];
BookExtended = [response1 valueForKey:#"Extended"];
BookReturned = [response1 valueForKey:#"Returned"];
NSLog(#"Book Name is %#", BookName);
[newBooksBorrowed addObject:BookName];
dispatch_sync(dispatch_get_main_queue(), ^{
// Update data source array and reload table view.
BooksBorrowed = newBooksBorrowed;
[self.tableView reloadData];
});
}
});
}
Are you sure bookName is a valid NSString? I would break at that line of code and type
po bookName
in the debugger to see if what you are assigning to bookName is in fact a valid NSString.
Oh, and make sure you returning a valid UITableViewCell at the end of that method, or else it is guaranteed your code will break.
Replace this code BooksBorrowed = newBooksBorrowed; with this in your function
BooksBorrowed = [[NSString alloc] initWithArray:newBooksBorrowed];
Hope it helps. Happy coding..
Thanks.
The solution to my questions was :
I had to change the part where I add my data into the table to :
NSString *string = [[NSString alloc] initWithFormat:#"%#",[BooksBorrowed objectAtIndex:indexPath.row]];
This is because a table view tends to not take things of element 0. Also I took out newBooksBorrowed and it works with just the BooksBorrowed array. :) Thank you everyone for helping me resolve it.

longpress custom items UICollectionViewCell image change

How can I make a cell imageview to change after longpress gesture?
With this one when I click on a cell (longpress) the 4 customized items appear but when I select one of them the app crashes. (if you remove :(Cell*)cell and cell.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"ICUbedRED.png"]]; it works...I mean the alertView appears but of course the image doesn't change).
- (void)longPress:(UILongPressGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
Cell *cell = (Cell *)recognizer.view;
[cell becomeFirstResponder];
UIMenuItem *highDep = [[UIMenuItem alloc] initWithTitle:#"High Dependency" action:#selector(hiDep:)];
UIMenuItem *lowDep = [[UIMenuItem alloc] initWithTitle:#"Low Dependency" action:#selector(lowDep:)];
UIMenuItem *booked = [[UIMenuItem alloc] initWithTitle:#"Booked" action:#selector(booked:)];
UIMenuItem *free = [[UIMenuItem alloc] initWithTitle:#"Free" action:#selector(free:)];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setMenuItems:[NSArray arrayWithObjects:booked, highDep, lowDep, free, nil]];
[menu setTargetRect:cell.frame inView:cell.superview];
[menu setMenuVisible:YES animated:YES];
}
}
the voids are:
- (void)hiDep:(Cell*)cell
{
NSLog(#"Bed is HiDep");
cell.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"ICUbedRED.png"]];
UIAlertView *testAlert = [[UIAlertView alloc] initWithTitle:#"This Bed is High Dependency"
message:#""
delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[testAlert show];
[testAlert release];
}
- (void)lowDep:(Cell*)cell
{.
cell.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"ICUbedYELLOW.png"]];
..}
- (void)free:(Cell*)cell
{..
cell.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"ICUbedGREEN.png"]];
.}
- (void)booked:(Cell*)cell
{..
cell.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"ICUbedBLUE.png"]];
.}
and the cell building method is:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Cell";
Cell *cvc = (Cell *)[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
int i = indexPath.row%[labelArray count];
number = i;
UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPress:)];
[cvc addGestureRecognizer:recognizer];
cvc.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"icubed.png"]];
cvc.label.text = [labelArray objectAtIndex:number];
return cvc;
}
#dottorfeelgood It is crashing for
cell.imageView.image = [UIImage imageNamed:[NSString stringWi......
because, the object retured as param to methods like
(void)lowDep:(Cell*)cell
is not of Class Cell, the retured param is of class UIMenuItem. because you are clicking on menuItems not Cell.
Instead of doing what you are doing now, you can use the MenuItems and corresponding actions on UICollectionCell solution provided by UICollectionView by default. You can check this tutorial here!
Just implement the 3 delegate methods and
// These methods provide support for copy/paste actions on cells.
// All three should be implemented if any are.
- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender;
- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender;
and set your custom menuItems needed to the sharedMenuController in ViewdidLoad.
Hope this helps, excuse my bad sentence forming.

Xcode: Remove objects from NSMutableArray based on NSDictionary

I am new to tableViews and dictionaries and i have a problem!
In ViewDidLoad i am initializing many MutableArrays and i am adding data using NSDictionary. Example:
- (void)viewDidLoad {
nomosXiou=[[NSMutableArray alloc] init];
[nomosXiou addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"Mary",#"name",#"USA",#"country", nil]];
[nomosXiou addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"Peter",#"name",#"Germany",#"country", nil]];
[super viewDidLoad];
// Do any additional setup after loading the view.}
In a previous ViewController the user selects a Country. Based on that selection, how could i remove from my arrays all the other entries???
Thanks in advance...
First note that your code fragment has an error. It should read:
NSMutableArray *nomosXiou= [[NSMutableArray alloc] init];
There are a number of ways to do what you want, but the most straightforward is probably the following:
NSString *countryName; // You picked this in another view controller
NSMutableArray *newNomosXiou= [[NSMutableArray alloc] init];
for (NSDictionary *entry in nomosXiou) {
if ([[entry objectForKey:#"country"] isEqualToString:countryName])
[newNomosXiou addObject:entry];
}
When this is done newNomosXiou will contain only the entries in nomosXiou that are from the country set in countryName.
Something like this will do the job:
NSMutableArray *nomosXiou = [[NSMutableArray alloc] init];
NSString *country = #"Germany"; // This is what you got from previous controller
// Some test data. Here we will eventually keep only countries == Germany
[nomosXiou addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"Mary",#"name",#"USA",#"country", nil]];
[nomosXiou addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"Peter",#"name",#"Germany",#"country", nil]];
[nomosXiou addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"George",#"name",#"Germany",#"country", nil]];
// Here we'll keep track of all the objects passing our test
// i.e. they are not equal to our 'country' string
NSIndexSet *indexset = [nomosXiou indexesOfObjectsPassingTest:^(id obj, NSUInteger idx, BOOL *stop){
return (BOOL)![[obj valueForKey:#"country"] isEqualToString:country];
}];
// Finally we remove the objects from our array
[nomosXiou removeObjectsAtIndexes:indexset];

NSMutableArray Not Adding Objects

I have a main view controller that consists of 1 button that when tapped, pushes a detail view controller and another button that simply launches a modal view controller that has a table. This detail view controller has a button that when tapped should add a new object to the array that was loaded by the table in the modal view controller.
Problem is, that add a new object button doesn't add to the NSMutableArray.
When I put a button in the main view and assigned the same method of adding objects to the NSMutableArray, it works. It just doesn't work when the button is placed on another view controller presented either via Navigation Controller and Modal View.
Here's my code when the button is pressed in the detail view controller:
- (IBAction)confirmBtnPressed
{
// Gets the current time and formats it
NSDate *timeNow = [NSDate date];
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
[timeFormatter setDateFormat:#"hh:mm a"];
// Gets the current date and formats it
NSDate *dateNow = [[NSDate alloc] init];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MMM dd, yyyy"];
NSString *currentTime = [timeFormatter stringFromDate:timeNow];
NSString *currentDate = [dateFormatter stringFromDate:dateNow];
NSString *timestamp = currentTime;
NSString *date = currentDate;
// This is where values gets saved
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:timestamp forKey:kTimeStampText];
[defaults setObject:date forKey:kDateText];
[defaults synchronize];
NSString *timeToday = [defaults objectForKey:kTimeStampText];
NSString *dateToday = [defaults objectForKey:kDateText];
tableVC.tableDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:timeToday, #"Time", dateToday, #"Date", nil];
[tableVC.tableArray addObject:tableVC.tableDict];
[tableVC.table reloadData];
}
Here's my code in the main view controller when the button to load the table modally is pressed:
// Table loaded
- (IBAction)viewHistoryPressed:(id)sender
{
if (!self.historyViewController)
{
self.historyViewController = [[HistoryViewController alloc] initWithNibName:#"HistoryViewController" bundle:nil];
}
[self presentModalViewController:historyViewController animated:YES];
}
Here's my viewDidLoad in my table view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *time = [defaults objectForKey:kTimeStampText];
NSString *date = [defaults objectForKey:kDateText];
tableDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:time, #"Time", date, #"Date", nil];
tableArray = [[NSMutableArray alloc] initWithObjects:tableDict, nil];
}
Screenshot of the main view:
detail view:
table view:
Try initializing your NSMutableArray with:
NSMutableArray *array = [NSMutableArray array];
Now you are open to adding entries.
Let me know if this works for you.
in viewDidLoad method... please use self.tableDict and self.tableArray while allocating them. 'self' calls the getter and setter methods so it is imp.

iPhone UITableViewCell slow performance

I just wrote a small application that read from a site feed and display in UITableViewCell. I am using custom view cell and my UITableView is screwed in scrolling like it is not very smooth in scrolling upside down. Any idea? Here's the code for my UITableViewCell,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:nil options:nil];
for(id currentObject in topLevelObjects) {
if([currentObject isKindOfClass:[UITableViewCell class]]) {
cell = (CustomCell *) currentObject;
break;
}
}
}
//MiceAppDelegate *AppDelegate = (MiceAppDelegate *)[[UIApplication sharedApplication] delegate];
if(dataArray != nil) {
//
//NSArray *promoArray = (NSArray *) promotions;
NSDictionary *datadict = [self.dataArray objectAtIndex:indexPath.row];
NSString *url = [datadict objectForKey:#"imageUrl"];
NSString *title = [datadict objectForKey:#"title"];
NSString *description = [datadict objectForKey:#"description"];
NSString *newAddressPartOfURL = [url stringByReplacingOccurrencesOfString:#" " withString:#"+"];
//NSLog([url stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]);
NSURLResponse *urlResponse;
NSData *data = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:newAddressPartOfURL]] returningResponse:&urlResponse error:nil];
// Configure the cell.
UIImage *urlImage = [[UIImage alloc] initWithData:data];
// NSLog(#"%i",[imageView.image topCapHeight]);
cell.title.text = title;
cell.description.text = description;
cell.image.image = urlImage;
[urlImage release];
}
return cell;
}
Doing synchronous downloads as your cells are being drawn is definitely going to cause some unsmooth scrolling. You could try to replace those with asynchronous calls, and filling in the data with a generic object while the download is happening. When the download completes, then call reloadData on your tableview.
afaik the dequeueReusableCellWithIdentifier method is called as cells get flush etc. Build your data / do the requests on init, not in the cell creation!

Resources