Reputation: 470
I'm using a Core Data model and a UITableViewController table view. My model seems to be working quite well however my table view is not updating when I add an entity to my model. The reason I believe my model is working is because when I add an entity nothing shows up in the view during run time, however if I cut the task then start it up new, suddenly the entity I previously created shows up in the table view.
Here is my table view controller - AudioTableViewController.h
#import <UIKit/UIKit.h>
#import "Bank.h"
#import "Player.h"
@class Player;
@interface AudioTableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource> {
Player *myMainMan;
}
-(void)addAudioEntityToArray:(AudioFile *)event;
-(NSMutableArray *)recordingsArray;
@end
AudioTableViewController.m (implementation file)
#import "AudioTableViewController.h"
@implementation AudioTableViewController
-(void)addAudioEntityToArray:(AudioFile *)event {
NSIndexPath *indexPath;
if(event.type) {
[[MusikerViewController recordingsArray] addObject:event];//self?
indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
}else {
[[MusikerViewController downloadsArray] addObject:event];
indexPath = [NSIndexPath indexPathForRow:0 inSection:1];
}
[[self tableView] setEditing:YES animated:NO];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
- (void)viewDidLoad {
[[self tableView] reloadData];
[super viewDidLoad];
self.title = @"Audio Files";//put this in application delegate
self.navigationItem.leftBarButtonItem = self.editButtonItem;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSLog(@"Place I");
if(section == 0) {
return [[MusikerViewController recordingsArray] count];
} else if (section == 1) {
return [[MusikerViewController downloadsArray] count];
}
}
... more methods
Here is part of my Bank class that might be relevant Bank.h
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import "AudioFile.h"
#import "AudioTableViewController.h"
#import "MusikerAppDelegate.h"
@interface Bank : NSObject <UIAlertViewDelegate> {
NSManagedObjectContext *managedObjectContext;
AudioFile *sound;
}
@property (retain, nonatomic) NSManagedObjectContext *managedObjectContext;
+(NSString *)getDataPath:(NSString *)fileExtDate;
-(AudioFile *)addAudioFileEntityToModelWithDate:(NSDate *)theD andURLString:(NSString *)str;
-(BOOL)removeAudioFromModel:(id)audio;
-(NSMutableArray *)getFetchArray;
@end
Bank.m
#import "Bank.h"
@implementation Bank
@synthesize managedObjectContext;
- (AudioFile *)addAudioFileEntityToModelWithDate:(NSDate *)theD andURLString:(NSString *)str {
sound = (AudioFile *)[NSEntityDescription insertNewObjectForEntityForName:@"AudioFile" inManagedObjectContext:managedObjectContext];
sound.creationDate = theD;
sound.soundPath = str; //set the sound path to the sound file's url
[self alertForTitle];
return sound;
}
- (BOOL)saveContext {
NSError *error = nil;
if(!managedObjectContext) {
NSLog(@"managedObejctContext problem at saveContext Bank");
}
if (![managedObjectContext save:&error]) {
return NO;
} else {
return YES;
}
}
- (NSMutableArray *)getFetchArray {
NSLog(@"ManagedObjectContext at getFetchArray");
NSLog(@"Context: %@",managedObjectContext);
NSFetchRequest *request = [[NSFetchRequest alloc] init];
if(!managedObjectContext) {
NSLog(@"There is no managedObjectContext in getFetchArray Bank");
}
NSEntityDescription *entity = [NSEntityDescription entityForName:@"AudioFile" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
NSLog(@"mutableFetchResults array is nil");
}
[request release];
return mutableFetchResults;
}
+ (NSString *)getDataPath:(NSString *)fileExtDate {
NSLog(@"getDataPath called");
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
documentsDirectory = [documentsDirectory stringByAppendingPathComponent:@"Musik Directory"]; //changing the recording directory to Musik Directory
NSError *error;
if (![[NSFileManager defaultManager] fileExistsAtPath:documentsDirectory]) {
[[NSFileManager defaultManager] createDirectoryAtPath:documentsDirectory withIntermediateDirectories:YES attributes:nil error:&error];
NSLog(@"In the if statement");
}
NSString *docPath = [documentsDirectory stringByAppendingPathComponent:fileExtDate];
return docPath;
}
Player.h
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import "Bank.h"
@class Bank;
@interface Player : NSObject <AVAudioPlayerDelegate, AVAudioRecorderDelegate> {
Bank *daBank;
AVAudioPlayer *musicPlayer;
AVAudioRecorder *musicRecorder;
NSDate *myDate;
NSString *strPath;
NSString *documentPath_;
NSMutableArray *arrayListOfRecordSound;
}
-(void)playSoundFile:(NSString *)soundFilePath;
-(BOOL)saveRecordingWithDate:(NSDate *)theD andURLString:(NSString *)str;
-(void)recordSomething;
-(void)playRecording;
-(void)play;
+ (NSString *)dateString:(NSDate *)date;
+ (NSString *)dateString;
@end
Player.m
- (Bank *)daBank
{
if(!daBank) {
daBank = [[Bank alloc] init];
}
return daBank;
}
-(BOOL)saveRecording { //this is the method that adds the new object to both the //model and view, the method that calls this method is not shown
Bank *B = [MusikerViewController daBank];
AudioTableViewController *ATVC2 = [MusikerViewController ATVControl];
AudioFile *myAudioFileMusicX314 = [[B addAudioFileEntityToModelWithDate:myDate andURLString:strPath] retain];
myAudioFileMusicX314.type = true;
[ATVC2 addAudioEntityToArray:myAudioFileMusicX314];
if(![B saveContext]) {
NSLog(@"addAudioFileEntityToModel is returning a nil managedObjectContext");
return NO;
}
[myDate release];
[strPath release];
[myAudioFileMusicX314 release];
[ATVC2 release];
return YES;
}
Last but not least, MusikViewController.h
#import <UIKit/UIKit.h>
#import "Player.h"
#import "Bank.h"
#import <QuartzCore/QuartzCore.h>
#import "MyButtonView.h"
#import "AudioTableViewController.h"
@class AudioTableViewController;
@class Bank;
@class Player;
@interface MusikerViewController : UIViewController {
] BOOL *pressed;
}
Player *myMainMan;
Bank *daBank;
AudioTableViewController *ATVControl;
NSMutableArray *recordingsArray;
NSMutableArray *downloadsArray;
+ (Bank *)daBank;
+ (Player *)myMainMan;
+ (AudioTableViewController *)ATVControl;
+ (NSMutableArray *)recordingsArray;
+ (NSMutableArray *)downloadsArray;
@end
MusikViewController.m
+ (NSMutableArray *)recordingsArray {
NSLog(@"recordingsArray called");
if(!recordingsArray) {
recordingsArray = [[NSMutableArray alloc] init];
NSMutableArray *bigTempArray = [[[[Bank alloc] init] autorelease] getFetchArray]; //change this
for(AudioFile *af in bigTempArray)
if(af.type) {
[recordingsArray addObject:af];
}
NSLog(@"recordingsArray exists");
}
return recordingsArray;
}
+ (NSMutableArray *)downloadsArray {
NSLog(@"recordingsArray called");
if(!downloadsArray) {
downloadsArray = [[NSMutableArray alloc] init];
// if(!bigTempArray)
NSMutableArray *bigTempArray = [[[[Bank alloc] init] autorelease] getFetchArray];
for(AudioFile *af in bigTempArray)
if(!af.type) {
[downloadsArray addObject:af];
}
}
return downloadsArray;
}
If there are any more methods that might be relevant, let me know and I will happily post them.
I should also mention that, I can add a single entity to the array after I launch the app, but after that its the same problem.
Upvotes: 6
Views: 3678
Reputation: 10195
In your addAudioEntityToArray
method your call to addObject
will add the new event to the END of the array, not the beginning.
Therefor the indexPath that you need to send to insertRowsAtIndexPaths
is: like [NSIndexPath indexPathForRow:[MusikerViewController recordingsArray].count-1 inSection:0]
Upvotes: 0
Reputation: 2242
Add [self.tableView reloadData]
into addAudioEntityToArray
method at the end. This will force the UITableView to reload from the model after each insertion.
Upvotes: 1
Reputation: 80265
I think your problem is the architecture of your view controllers. Try this:
1) Set up all the core data stack in the app delegate. Pass the associated managed object context to all your view controllers as a property. That is the pattern Apple uses in many of its sample code examples.
2) For each table view controller, create its own NSFetchedResultsController
, normally also as a property. Use the Apple samples as a guide.
3) Never fetch any data from another view controller, as you do in your code. You cannot and should not get the table data for the AudioTableViewController
from the MusikerViewController
.
It is possible and sometimes useful to have a central data object that provides data to view controllers. You cannot have this data object be a view controller. This is a blatant (and in your case fatal) violation of the MVC design pattern. Your error most likely stems from that (because MusikerViewController
is not on screen and may even be deallocated).
4) Make sure that in your datasource
methods you use only the fetched results controller to populate the tables and deliver media.
Upvotes: 3
Reputation: 19946
I suggest using a fetchresultscontroller, I used arrays before, but much better with FRC.
Upvotes: 0
Reputation: 3130
May be your - (void)addAudioEntityToArray:(AudioFile *)event {} method is called from secondary thread (other than MainUi thread) so that directly reloading table will not work.
try instead
[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
Hope it Helps!!
Upvotes: 5
Reputation: 8928
You're setting eventsArray via setter:
[self setEventsArray:[daBank getFetchArray]];
Why don't you access it via getter? You might be using another instance of array
self.eventsArray
or [self eventsArray]
Upvotes: 0