TableViewCell doesn't update correctly - xcode4

I have this tableviewcell.m to configure my cells.
It is configuring the text and information correctly but I just can't get it to update the color according to some other information.
Here's the code:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
priceLabel = [[UILabel alloc] initWithFrame:CGRectZero];
priceLabel.textAlignment = UITextAlignmentRight;
[priceLabel setFont:[UIFont systemFontOfSize:12.0]];
if ([account.income isEqualToString:#"income"]){
[priceLabel setTextColor:[UIColor greenColor]];
} else if ([account.income isEqualToString:#"expense"]) {
[priceLabel setTextColor:[UIColor redColor]];
} //label, alignment, font are working correctly
//but the if statement doesn't get there
}
The color though, not working at all.
It seems to me that the if statement is being completely ignored.
Could anyone help me to understand why or suggest a better programming approach ?
Here's the cell for row code. I don't know if it will help because they aren't in the same file. Here I'm only referencing my tableviewcell file:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// create a TableViewCell, then set its account to the account for the current row.
static NSString *AccountCellIdentifier = #"AccountCellIdentifier";
TableViewCell *accountCell = (TableViewCell *)[tableView dequeueReusableCellWithIdentifier:AccountCellIdentifier];
if (accountCell == nil) {
accountCell = [[[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:AccountCellIdentifier] autorelease];
accountCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
[self configureCell:accountCell atIndexPath:indexPath];
return accountCell;
}
//and here the cell config
- (void)configureCell:(TableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// Configure the cell
Account *account = (Account *)[fetchedResultsController objectAtIndexPath:indexPath];
cell.account = account;
}
Many thanks !
Here's the code where i get the texts:
- (void)setAccount:(Account *)newAccount {
if (newAccount != account) {
[account release];
account = [newAccount retain];
}
nameLabel.text = account.name;
accountLabel.text = Account.accounttype;
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *stringcost = [numberFormatter stringFromNumber:account.cost];
priceLabel.text = stringcost;
}

Yes! I knew I was missing something simple.
All I had to do is "move" that If... statement to where the implementation of the cell is setting the text. There and only there it will update the color (or anything else) so here's my final code that's working perfectly now...
- (void)setAccount:(Account *)newAccount {
if (newAccount != account) {
[account release];
account = [newAccount retain];
}
nameLabel.text = account.name;
accountLabel.text = Account.accounttype;
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *stringcost = [numberFormatter stringFromNumber:account.cost];
priceLabel.text = stringcost;
if ([account.income isEqualToString:#"income"]){
[priceLabel setTextColor:[UIColor greenColor]];
} else if ([account.income isEqualToString:#"expense"]) {
[priceLabel setTextColor:[UIColor redColor]];
} //this will give me green text color for income and red text color for expense
}
Special thanks for Michael Dauterman who inspired me to stay awake for hours through the night 'till my function is actually working.

Related

iOS table preview image release

I'm testing an RSS on my iPhone. It uses 0 nib files. I'll try to describe it as best as I can, and will post code if its required, but I bet its a common phenomena with a common solution. The issue is in a tableviewcontroller, and the solution probably needs to be implemented in the CellForRowAtIndexPath method. If I scroll down, preview images stay in their respective spots until the async queue loads the correct image for that cell. So if I have an image for array item 1, and I scroll down to array item 20, the image for array item 1 will still be there until my queue catches up and loads that image. How can I release the images from cells that I am not viewing? Thank you for your time.
Here is my CellForRow...
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier];
}
ArticleItem *object = _objects[indexPath.row];
cell.primaryLabel.text = object.title;
cell.secondaryLabel.text = object.strippedDescription;
cell.primaryLabel.lineBreakMode = NSLineBreakByWordWrapping;
cell.primaryLabel.numberOfLines = 0;
cell.primaryLabel.lineBreakMode = NSLineBreakByWordWrapping;
cell.secondaryLabel.numberOfLines = 0;
//Async dispatch queue for image preview loading...
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
UIImage *preview = nil;
if (object.iG = nil)
{
preview = [UIImage imageNamed:#"CellLogo.png"];
}
else
{
preview = [UIImage imageWithData:object.iG];
}
dispatch_sync(dispatch_get_main_queue(), ^{
[[cell myImageView] setImage:preview];
[cell setNeedsLayout];
});
});
return cell;
}
If you gather, I have an ArticleItem class which pulls the image URLS and turns them into data , and I have a CustomCell class which does what its called.
CustomCell.h
#interface CustomCell : UITableViewCell {
UIImageView *myImageView;
}
#property(nonatomic,strong)UIImageView *myImageView;
#end
=====================================================
CustomCell.m
- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) {
// Initialization code
myImageView = [[UIImageView alloc]init];
[self.contentView addSubview:myImageView];
}
return self;
}
-(void)viewDidUnload {
myImageView = nil;
primaryLabel = nil;
secondaryLabel = nil;
}
Implement a subclass of UITableViewcell, make a property for imageview. As soon as it gets away from visibility, it will be released. Describing just the overview as you may yourself need to see the usage upon scrolling.

How to fix UISearchBar returning NSRangeException when clear button is clicked? (FIXED!!!)

I have implemented a UISearchBar in my app that is crashing when I hit the clear button and while there's one item found. It's like I type in some character, the app searches and display 1 item, but I when I clear the search, it crashes.
I searched stackoverflow and I am aware that the problem is with the array that holds the search items cause when I hit the clear button the array becomes empty and the tableview index path.row can't be displayed.
Also, if the search returns no item and I hit the clear button I get a similar error message buy this time saying the I got an empty array.
The app stops here:
NSDictionary *itemAtIndice =(NSDictionary *)[filteredCodigos objectAtIndex:indexPath.row];
The problem is that I simple don't know what to do!!!
Here is the error:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
And here is my code::
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchText.length == 0) {
isFiltered = NO;
} else {
isFiltered = YES;
filteredCodigos = [[NSMutableArray alloc]init];
for (NSDictionary *item in values) {
NSString *string = [item objectForKey:#"NAME"];
NSRange stringRange = [string rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (stringRange.location != NSNotFound) {
[filteredCodigos addObject:item];
}
}
}
[self.tableView reloadData];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self.Pesquisa resignFirstResponder];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (isFiltered) {
return [filteredCodigos count];
}
return values.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSDictionary *itemAtIndex =(NSDictionary *)[values objectAtIndex:indexPath.row];
NSDictionary *itemAtIndice =(NSDictionary *)[filteredCodigos objectAtIndex:indexPath.row];
if (!isFiltered) {
cell.textLabel.text = [itemAtIndex objectForKey:#"SYMBOL"];
cell.detailTextLabel.font = [UIFont systemFontOfSize:10];
cell.detailTextLabel.text = [itemAtIndex objectForKey:#"NAME"];
} else {
cell.textLabel.text = [itemAtIndice objectForKey:#"SYMBOL"];
cell.detailTextLabel.font = [UIFont systemFontOfSize:10];
cell.detailTextLabel.text = [itemAtIndice objectForKey:#"NAME"];
}
return cell;
}
filteredCodigos is declared outside of searchBar:textDidChange: and is used in multiple places but is assigned to in searchBar:textDidChange:. Most likely, some other code is trying to access members of filteredCodigos which is unassigned or empty. Enabling exception breakpoints will help you track it down.
As a side note. You might look at NSPredicate to filter your items instead of the for loop.
Finally managed to fix this issue.
I just replaced indexPath.row for lastObject at the line that was giving me the error:
So, before:
NSDictionary *itemAtIndice =(NSDictionary *)[filteredCodigos objectAtIndex:indexPath.row];
And after:
NSDictionary *itemAtIndice =(NSDictionary *)[filteredCodigos lastObject];

AVAudioPlayer Notification issue

So I'm almost done with my app and I've hit a wall and cannot get around this final problem.
I basically have 2 view's. A main page and the game play screen.
On the first play the game works fine, but when i leave the main screen and then return to the game screen all the sounds are duplicating and firing the the playerItemDidReachEnd early (because I'm guessing there are 2 instances of it, but it cannot seem to get the player to stop this. Here is the basic code causing this. Any help would go a long way, thanks. I'm not sure if my issue is i'm creating multiple instances of View2 in View1 or if I'm creating multiple player objects in view2 thus duplicating the notification.
I know there is a lot going on in my - (void)playerItemDidReachEnd:(NSNotification *)notification, but it works fine on the first load of the page, its only when I click "go back to view1" and then go back in to View2 that the issue happens.
View1ViewController.h
----------------------
#import "(i know here are arrows here, but can't make them show)UIKit/UIKit.h>
#import "ApplicationViewController.h"
#interface MonsterSpellViewController : UIViewController {
}
-(IBAction)showView1;
View2ViewController.m
----------------------
-(IBAction)showView2{
ApplicationViewController *view2 = [[ApplicationViewController alloc]initWithNibName:#"ApplicationViewController" bundle:nil];
view2.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:view2 animated:YES];
}
View2ViewController.h
------------------------
#import "(i know here are arrows here, but can't make them show)UIKit/UIKit.h>
#import "(i know here are arrows here, but can't make them show)AVFoundation/AVFoundation.h>
#class AVAudioPlayer;
#interface ApplicationViewController : UIViewController{
AVAudioPlayer *avPlayer;
}
View2ViewController.m
-------------------------
#import "View2ViewController.h"
#synthesize avPlayer;
-(AVAudioPlayer *)avPlayer {
if(!avPlayer) avPlayer = [[AVAudioPlayer alloc]init];
return avPlayer;
}
-(void) viewDidLoad
{
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:avPlayer];
}
-(IBAction)playSoundTest
{
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/monster3.mp3", [[NSBundle mainBundle] resourcePath]]];
self.avPlayer = [AVPlayer playerWithURL:url];
[self.avPlayer play];
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
//[player seekToTime:kCMTimeZero];
if (playEscape == YES) {
[self btnEscapeSound];
playEscape = NO;
}
if ((startButton.hidden == NO) && (letterCount != -1) && (playFinal == YES))
{
[self btnFinalSound];
playFinal = NO;
playEscape = YES;
}
NSLog(#"Player Check accessed");
if (letterCount == 3) {
if (Winner == letterCount) {
//moveNextSound = YES;
if (intLoopCount < 104)
{
if (intLoopCount<104) {
[self btnStartOver:intLoopCount];
playFinal = NO;
//intLoopCount++;
}
if (intLoopCount==104) {
startButton.hidden=NO;
playFinal = YES;
}
}
}
}
if (letterCount == 4) {
if (Winner == letterCount) {
//moveNextSound = YES;
if (intLoopCount < 105)
{
[self btnStartOver:intLoopCount];
//intLoopCount++;
if (intLoopCount==105) {
startButton.hidden=NO;
playFinal = YES;
}
}
}
}
}
}
-(IBAction)goBack:(id)sender{
[self dismissModalViewControllerAnimated:YES];
}
Try adding [view2 release]; after [self presentModalViewController:view2 animated:YES];

Loading database at start up slows down the app

i m not sure how to describe this as i m new with all the developing and i m really looking forward to an answer from you guys. I know you can be very busy but please try to HELP me!
Here it goes. I have an app that loads a very large database (although it only has 100 entries it contains HiRes images (100MB) ).
At start up a tableview presents the rows -records (using only 3 attributes from the database). However it seems that the WHOLE database (including the images) is loaded at start up!
IS THERE A WAY TO ONLY LOAD THE 3 attributes (something like "select") when the app starts and then when the user moves to didselectrowatindexpath load the rest of the record?
Because i have NO IDEA where to look or what to do i would appreciate some coding help!
here is the code i m using:
#pragma mark -
#pragma mark App support
- (NSFetchedResultsController *)resetFetchedResultsController:(NSPredicate *)predicate cached:(BOOL)cached
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Records" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *partDescriptor = [[NSSortDescriptor alloc] initWithKey:#"displayOrder" ascending:YES];
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: partDescriptor, nameDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
if (predicate != nil)
[fetchRequest setPredicate:predicate];
NSString *cacheName = nil;
if (cached)
cacheName = #"Root";
NSFetchedResultsController *aFetchedResultsController = [[[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil
cacheName:cacheName] autorelease];
aFetchedResultsController.delegate = self;
[fetchRequest release];
[partDescriptor release];
[nameDescriptor release];
[sortDescriptors release];
NSError *error = nil;
if (![aFetchedResultsController performFetch:&error]) {
// Handle error
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
return aFetchedResultsController;
}
- (void)showRecords:(Records *)records animated:(BOOL)animated {
.
RecordsDetailViewController *detailViewController = [[RecordsDetailViewController alloc] initWithStyle:UITableViewStyleGrouped];
detailViewController.records = records;
[self.navigationController pushViewController:detailViewController animated:animated];
[detailViewController release];
}
#pragma mark -
#pragma mark Table view methods
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.backgroundColor = [UIColor lightGrayColor];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSInteger count = [[fetchedResultsController sections] count];
if (count == 0) {
count = 1;
}
return count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger numberOfRows = 0;
if ([[fetchedResultsController sections] count] > 0) {
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
numberOfRows = [sectionInfo numberOfObjects];
}
return numberOfRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *RecordCellIdentifier = #"RecordCellIdentifier";
RecordTableViewCell *recordCell = (RecordTableViewCell *)[tableView dequeueReusableCellWithIdentifier:RecordCellIdentifier];
if (recordCell == nil) {
recordCell = [[[RecordTableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:RecordCellIdentifier] autorelease];
recordCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
[self configureCell:recordCell atIndexPath:indexPath];
return recordCell;
}
- (void)configureCell:(RecordTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// Configure the cell
Records *records = (Records *)[fetchedResultsController objectAtIndexPath:indexPath];
cell.records = records;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.searchDisplayController.isActive)
[self.tableView reloadData];
Records *records = (Records *)[fetchedResultsController objectAtIndexPath:indexPath];
[self showRecords:records animated:YES];
}
//this is from the RecordTableViewCell.m to show you the attributes i m using:
#pragma mark -
#pragma mark Record set accessor
- (void)setRecord:(Record *)newRecord {
if (newRecord != record) {
[record release];
record = [newRecord retain];
}
imageView.image = [UIImage imageNamed:#"icon.png"];
nameLabel.text = record.name;
overviewLabel.text = record.overview;
partLabel.text = record.part;
}
thanks again...
I would separate the large file from the metadata, because I like to have the freedom to manage these expensive resources seParately. Then I could store them differently, eg filesystem, or http server. This allows me to cache them or send them to remote locAtions proactively to reduce the download times
The rest of the table can then fit in less blocks in the database so less disk access is needed. Many databases do this internally anyway, eg postgresql
You can the just refer to the heavy resource by Id
Ok here it goes. I ve gave up the idea of loading separately the attributes that i need at start up.
What i ve done AND NOW WORKS FLAWLESSLY is to do create RELATIONSHIPS in my model. Images are now loading only when called!
This solution was in my mind but because i had already populated my database it was difficult for me to repeat this step.
However i m glad that i did!
NOW it works as it should!!
Happy Developer!!

How to load UIImagePickerController at viewLoad

This seems like a really simple idea... I have a button that says "load a picture". When that button is clicked I want to remove the current view, load a new one, open the image picker, get the selected picture, and display it in the view that I just loaded. I have read several documents that say UIImagePicker does not work in viewDidLoad, and found one thread that suggested using awakeFromNib instead but even that does not work... here is code. Please help.
In MenuViewController
-(IBAction)loadPictureButtonPressed
{
UIView *parent = [self.view superview];
if(self.loadPictureViewController.view.superview == nil)
{
if(self.loadPictureViewController == nil)
{
LoadPictureViewController *picController = [[LoadPictureViewController alloc]
initWithNibName:#"LoadPictureView" bundle: nil];
self.loadPictureViewController = picController;
[picController release];
}
}
[parent addSubview:self.loadPictureViewController.view];
[self.view removeFromSuperview];
}
In LoadPictureViewController
-(void)awakeFromNib
{
if([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypePhotoLibrary])
{
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:picker animated:YES];
[picker release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Error!"
message:#"Device does not support photo library";
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}
Again I have tried placing this code in both viewDidLoad and awakeFromNib. Please help
I simply set an NSTimer in viewDidLoad with a timer of 0 to select the method where I load it.
[NSTimer scheduledTimerWithTimeInterval:0 target:self selector:#selector(camera) userInfo:nil repeats:NO];
Instead of NSTimer, you probably want to use the following in -viewDidLoad,
[self performSelector:#selector(camera) withObject:nil afterDelay:0];

Resources