Loading database at start up slows down the app - sqlite

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!!

Related

Loading an audio sample from the documents folder

I'm trying to have an app play audio files added via itunes file-sharing. I've managed the app to retrieve the app's sandbox folder's content, but I'm not able to load such files into a C4Sample by specifying the complete path.
NSString *documentsFolder;
NSString *clickAudioPath;
C4Sample *clicksample;
-(void)setup {
// Retrieve the app's Documents folder
documentsFolder = [self applicationDocumentsDirectory];
clickAudioPath = [NSString stringWithFormat:#"%#/click.mp3", documentsFolder];
// Add test click audio
clicksample = [C4Sample sampleNamed:clickAudioPath];
[clicksample prepareToPlay];
[clicksample play];
}
// Get Documents folder
- (NSString *) applicationDocumentsDirectory{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
The above code doesn't play any sound, although I've doubled checked that clicksample actually refers to an existing file. How can I specify a complete path instead of just a name to load the audio?
Add a new method as below.
-(id) initWithURL:(NSURL *) soundFileURL
{
self = [super init];
if(self != nil) {
_player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
self.enableRate = YES;
self.player.delegate = self;
[self setup];
}
return self;
}

Saving an ALAsset to SQLite3 database - retrieve error

I'm trying to save a list of assets to upload in a sqllite3 db, but when i parse the database and set the assets to an array, then try to use the asset i get a SIGABRT error.
ALAsset *asset = (ALAsset *) assets[indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"image%d: ready to upload.",indexPath.row];
cell.detailTextLabel.text = #"1.3MB to folder <server folder>";
[[cell imageView] setImage:[UIImage imageWithCGImage:[asset thumbnail]]];// SIGABRT ERROR
Im saving the ALAsset to the database as a string (TEXT) with UTF8formatting
NSMutableArray *tmpArray = [NSMutableArray alloc]init];
///get sql
[tmpArray addObject:someStringFromSQL];
///end sql loop
assets = [tmpArray mutableCopy];
in the code above I tried:
[[cell imageView] setImage:[UIImage imageWithCGImage:[(ALAsset *) asset thumbnail]]];// SIGABRT ERROR
and that didn't work.
This is the error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString thumbnail]: unrecognized selector sent to instance 0xc0a7800'
Any suggestions?
Also as a side question: Does anyone know how to get the file size (i.e. 1.3MB) from the asset?
BLOCK:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
//do stuff in cell
NSURL *aURL =[NSURL URLWithString:[assets objectAtIndex:indexPath.row]];
[assetsLibrary assetForURL:aURL resultBlock:^(ALAsset *asset){
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = [UIImage imageWithCGImage:[asset thumbnail]];
});
[[NSNotificationCenter defaultCenter] postNotificationName:#"newAssetImageRetrieved" object:nil];
//in this notificaton I'm reloading the data; its putting the tableview in an infinite loop - but the images display...
}
failureBlock:^(NSError *error){
// error handling
NSLog(#"Can't get to assets: FAILED!");
}];
//cell.imageView.image = [UIImage imageWithCGImage:[asset thumbnail]];
cell.textLabel.text = [NSString stringWithFormat:#"image%d: ready to upload.",indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:#"1.3MB to folder %#", [destinations objectAtIndex:indexPath.row]];
//[[cell imageView] setImage:[UIImage imageWithCGImage:[asset thumbnail]]];
return cell;
}
There are a couple of issues with your code sample:
The image retrieval is happening asynchronously, so when you try to update the image, you want to make sure the cell is still visible (and not reused for another NSIndexPath).
In this case, the retrieval from the ALAssetsLibrary will probably be so fast that this isn't critical, but it's a good pattern to familiarize yourself with, because if you're ever retrieving images over the Internet, this issue becomes increasingly important.
Because cells are being reused, if you don't find the image immediately and have to update it asynchronously, make sure you reset the UIImageView before initiating the asynchronous process. Otherwise, you'll see a "flickering" of replacing old images with new ones.
You are using UITableViewCell for your cell. The problem with that is that it will layout the cell based upon the size of the image present by the time cellForRowAtIndexPath finishes.
There are two easy solutions to this. First, you could initialize the cell's imageView to be a placeholder image of the correct size. (I usually have an image called placeholder.png that is all white or all transparent that I add to my project, which is what I used below.) This will ensure that cell will be laid out properly, so that when you asynchronously set the image later, the cell will be laid out properly already.
Second, you could alternatively use a custom cell whose layout is fixed in advance, bypassing this annoyance with the standard UITableViewCell, whose layout is contingent upon the initial image used.
I'd suggest using a NSCache to hold the thumbnails images. That will save you from having to constantly re-retrieve the thumbnail images as you get them from your ALAssetsLibrary as you scroll back and forth. Unfortunately, iOS 7 broke some of the wonderful NSCache memory-pressure logic, so I'd suggest a cache that will respond to memory pressure and purge itself if necessary.
Anyway, putting that all together, you get something like:
#interface ViewController ()
#property (nonatomic, strong) NSMutableArray *assetGroups;
#property (nonatomic, strong) ALAssetsLibrary *library;
#property (nonatomic, strong) ThumbnailCache *imageCache;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.imageCache = [[ThumbnailCache alloc] init];
self.assetGroups = [NSMutableArray array];
self.library = [[ALAssetsLibrary alloc] init];
[self.library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (!group) {
[self.tableView reloadData];
return;
}
CustomAssetGroup *assetGroup = [[CustomAssetGroup alloc] init];
assetGroup.name = [group valueForProperty:ALAssetsGroupPropertyName];
assetGroup.assetURLs = [NSMutableArray array];
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result) {
[assetGroup.assetURLs addObject:[result valueForProperty:ALAssetPropertyAssetURL]];
}
}];
[self.assetGroups addObject:assetGroup];
} failureBlock:^(NSError *error) {
NSLog(#"%s: enumerateGroupsWithTypes error: %#", __PRETTY_FUNCTION__, error);
}];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.assetGroups.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
CustomAssetGroup *group = self.assetGroups[section];
return [group.assetURLs count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
CustomAssetGroup *group = self.assetGroups[section];
return group.name;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// note, these following three lines are unnecessary if you use cell prototype in Interface Builder
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
CustomAssetGroup *group = self.assetGroups[indexPath.section];
NSURL *url = group.assetURLs[indexPath.row];
NSString *key = [url absoluteString];
UIImage *image = [self.imageCache objectForKey:key];
if (image) {
cell.imageView.image = image;
} else {
UIImage *placeholderImage = [UIImage imageNamed:#"placeholder.png"];
cell.imageView.image = placeholderImage; // initialize this to a placeholder image of the right size
[self.library assetForURL:url resultBlock:^(ALAsset *asset) {
UIImage *image = [UIImage imageWithCGImage:asset.thumbnail]; // note, use thumbnail, not fullResolutionImage or anything like that
[self.imageCache setObject:image forKey:key];
// see if the cell is still visible, and if so, update it
// note, do _not_ use `cell` when updating the cell image, but rather `updateCell` as shown below
UITableViewCell *updateCell = (id)[tableView cellForRowAtIndexPath:indexPath]; // not to be confused with similarly named table view controller method ... this one checks to see if cell is still visible
if (updateCell) {
[UIView transitionWithView:updateCell.imageView duration:0.1 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
updateCell.imageView.image = image;
updateCell.textLabel.text = asset.defaultRepresentation.filename;
} completion:nil];
}
} failureBlock:^(NSError *error) {
NSLog(#"%s: assetForURL error: %#", __PRETTY_FUNCTION__, error);
}];
}
return cell;
}
#end
The above uses the following classes:
/** Thumbnail cache
*
* This cache optimizes retrieval of old thumbnails. This purges itself
* upon memory pressure and sets a default countLimit.
*/
#interface ThumbnailCache : NSCache
// nothing needed here
#end
#implementation ThumbnailCache
/** Initialize cell
*
* Add observer for UIApplicationDidReceiveMemoryWarningNotification, so it purges itself under memory pressure
*/
- (instancetype)init
{
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(removeAllObjects) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
self.countLimit = 50;
};
return self;
}
/** Dealloc
*
* Remove observer before removing cache
*/
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
}
#end
and
/** Custom AssetGroup object
*
* This is my model object for keeping track of the name of the group and list of asset URLs.
*/
#interface CustomAssetGroup : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, strong) NSMutableArray *assetURLs;
#end
#implementation CustomAssetGroup
// nothing needed here
#end
You have to explore all the code base related to the save and retrieve functionality.
However, here are some good tips.
Save the ALAsset Url instead of saving the entire ALAsset as a string.
Retrieve the ALAsset Url from the database and convert it to NSUrlString.
Use ALAsset Library to load the image or thumbnail back.
Hope this will help you.

AVAudioPlayer sounds garbled on iPhone without headphones

I have 23 music files (10-20 seconds in length) that I want to play when the user selects them and presses the play button. It works find on my iPad and on the simulators, with or without earphones. But on the iPhone device without earphones, around 80% of the files sound garbled, the volume is low, and some are barely legible. I can plug the earphones in, and they sound fine. As soon as I unplug the earphones, the sounds are garbled again.
Since some of the files always play fine, I converted all the original mp3's that I was using into the AAC format with a sample rate of 44100. But the same files play fine, while most are distorted when playing on the iphone device.
I've tried several settings for AVAudioSession category: playback, playAndRecord, ambient. I've tried storing the files in core data and using initWithData instead of initWithContentsOfURL. Can anyone suggest what else I might try? Or how I might get clues into why I'm having this problem?
Here is my code. There are 3 relevant files. The ViewController that has a button to play a selected music file, an AVPlaybackSoundController that has all the audio logic, and a Singleton that has an array with the filenames.
My ViewController creates an AVPlaybackSoundController through the Nib.
IBOutlet AVPlaybackSoundController *avPlaybackSoundController;
#property (nonatomic, retain) AVPlaybackSoundController *avPlaybackSoundController;
- (IBAction) playButtonPressed:(id)the_sender
{
self.currentRhythmSampleIndex = arc4random() % [[CommonData sharedInstance].rhythmSampleArray count];
[self.avPlaybackSoundController playMusic:self.currentRhythmSampleIndex];
self.playBtn.hidden=YES;
self.pauseBtn.hidden=NO;
}
AVPlaybackSoundController.m
- (void) awakeFromNib
{
[self initAudioSession:AVAudioSessionCategoryPlayback];
[self initMusicPlayer];
}
- (void) initAudioSession:(NSString *const)audioSessionCategory
{
NSError* audio_session_error = nil;
BOOL is_success = YES;
is_success = [[AVAudioSession sharedInstance] setCategory:audioSessionCategory error:&audio_session_error];
if(!is_success || audio_session_error){
NSLog(#"Error setting Audio Session category: %#", [audio_session_error localizedDescription]);
}
[[AVAudioSession sharedInstance] setDelegate:self];
audio_session_error = nil;
is_success = [[AVAudioSession sharedInstance] setActive:YES error:&audio_session_error];
if(!is_success || audio_session_error){
NSLog(#"Error setting Audio Session active: %#", [audio_session_error
localizedDescription]);
}
}
- (void) initMusicPlayer
{
NSError* file_error = nil;
NSURL* file_url = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"musicFile1" ofType:#"m4a"]
isDirectory:NO];
avMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:file_url
error:&file_error];
if(!file_url || file_error){
NSLog(#"Error loading music file: %#", [file_error
localizedDescription]);
}
self.avMusicPlayer.delegate = self;
self.avMusicPlayer.numberOfLoops = 0xFF;
[file_url release];
}
-(void) playMusic:(NSUInteger)rhythmSampleIdx
{
CommonData *glob = [CommonData sharedInstance];
if (rhythmSampleIdx > [glob.rhythmSampleArray count])
return; // bug if we hit here
// if we were already playing it, just resume
if ((self.avMusicPlayer) && (rhythmSampleIdx == self.currentRhythmSampleIndex)){
[self.avMusicPlayer play];
}
else{ // re-init player with new rhythm
if (self.avMusicPlayer){
[self.avMusicPlayer stop];
[self.avMusicPlayer setCurrentTime:0.0];
}
NSError* error = nil;
RhythmSample *rhythmSample = [glob.rhythmSampleArray objectAtIndex:rhythmSampleIdx];
NSString* rhythm_filename = [self getRhythmFileName:rhythmSampleIdx];
NSURL* file_url = [[[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle]
pathForResource:rhythm_filename ofType:#"m4a"] isDirectory:NO]autorelease];
self.avMusicPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:file_url error:&error]autorelease];
[self.avMusicPlayer prepareToPlay]; // shouldn't be needed since we are playing immediately
if(error){
NSLog(#"Error loading music file: %#", [error localizedDescription]);
}else{
self.avMusicPlayer.delegate = self;
self.avMusicPlayer.numberOfLoops = 0xFF; // repeat infinitely
self.currentRhythmSampleIndex = rhythmSampleIdx;
[self.avMusicPlayer play];
}
}
}
I finally decided to obtain the sound files from a different source. The new sound files play fine. I still have no theory as to why the old sound files would play with earphones, but not without them. I really dislike finding solutions without understanding why they work.

TableViewCell doesn't update correctly

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.

Help with UITableView / Navigation Setup with UITabBar Interface

I'm trying to set up a Tab Bar Application as my root controller, and one of the tabs to be a Navigation setup. On my Root View Controller of the Navigation View, I have one child level that is a subclass of the UIViewController called IntervalViewController.
I have this in my Root View Controller (IntervalSetupViewController.m):
#import "IntervalSetupViewController.h"
#import "IntervalViewController.h"
#implementation IntervalSetupViewController
#synthesize controllers; // My Array for the Table View Cells
- (void)viewDidLoad {
self.title = #"Interval Setup";
NSMutableArray *array = [[NSMutableArray alloc] init];
// Interval List Setup
IntervalViewController *newInterval = [[IntervalViewController alloc]
initWithStyle:UITableViewStylePlain];
newInterval.title = #"Interval 1";
[array addObject:newInterval];
[newInterval release];
self.controllers = array;
[array release];
[super viewDidLoad];
}
- (void)viewDidUnload {
self.controllers = nil;
[super viewDidUnload];
}
- (void)dealloc {
[controllers release];
[super dealloc];
}
#pragma mark -
#pragma mark Table Data Source Methods
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
return [self.controllers count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *IntervalCell = #"IntervalCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:IntervalCell];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:IntervalCell] autorelease];
}
// Configure the cell
NSUInteger row = [indexPath row];
IntervalViewController *newController = [controllers objectAtIndex:row];
cell.textLabel.text = newController.title;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
#pragma mark Table View Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = [indexPath row];
IntervalViewController *nextController = [self.controllers objectAtIndex:row];
[self.navigationController pushViewController:nextController animated:YES];
}
#end
This is the error screen from the console:
* -[IntervalViewController initWithStyle:]: unrecognized selector sent to instance 0x3b33e60
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[IntervalViewController initWithStyle:]: unrecognized selector sent to instance 0x3b33e60'
I assume that I am passing an invalid argument to my initWithStyle method, but I thought UITableViewStylePlain was a valid parameter. Am I setting this up right? I was following the example in APress Beginning iPhone Development 3 book and trying to modify it a little to what I wanted to do, but I'm new to coding. Thanks!
initWithStyle is used to initialize a UITableViewController not a UIViewController

Resources