I need help restructuring my method with better logic
Update:
I' having this problem with this method: By default, the view sets the day to today and creates a session what today's date as its timeStamp unless the user changes the date manually.
If I add exercise to today's date, everything is fine.
If I choose a previous date and add an exercise to it, it seems fine, but it seems that exercise is added not only to this previous date, but also to today.
So no matter what previous date I choose, the exericse entity is added to that session and to today's session.
Therefore when I view today's session in tableview, it has all exercises every done because everything is added to today along with its manually chosen date.
How can I fix this?
Original:
I have a detailViewController that is responsible for dealing with Core Data objects Session, Exercise, & Set.
The view's purpose is for the user to enter detail about their fitness workout. By default, the Date is set to today but the user can change it to a previous date. In createSession
, a new Session object with timestamp of that date is created when the user presses the done button for that date and if the date doesn't already exist. If it already exists, it fetches that object with that timeStamp date.
The problem is, this creates a new object of Session even if the user does not enter the necessary data later. After the Session is created, the user is prompted to enter weight and reps used for the exercise. If the user doesn't enter this information (object Set), there is a Session object that has no purpose because their are no exercises and set objects related to it.
But the reason I create the Session object before checking for weight/rep is because if a Session is fetched, I want to display its property data in the view, thus I need to work with it before adding sets/reps.
My current code is:
-(void)createSession
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat: @"(timeStamp >= %@ && timeStamp <= %@)", targetDateBegins, targetDateEnds]];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Session" inManagedObjectContext:managedObjectContext]];
NSError *error = nil;
NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(@"Fetch error: %@", error);
if ([results count])
{
session = (Session *)[results objectAtIndex:0];
}
else
{
session = (Session *)[NSEntityDescription insertNewObjectForEntityForName:@"Session" inManagedObjectContext:managedObjectContext];
session.timeStamp = self.picker.date;
}
NSSet *filteredExercisesFromSession=[session.exercises filteredSetUsingPredicate:[NSPredicate predicateWithFormat: @"name == %@",selectedExerciseName]];
if ([filteredExercisesFromSession count] > 0)
{
self.exercise=[filteredExercisesFromSession anyObject];
}
else
{
self.exercise = (Exercise *)[NSEntityDescription insertNewObjectForEntityForName:@"Exercise" inManagedObjectContext:managedObjectContext];
self.exercise.name = selectedExerciseName;
[session addExercisesObject:exercise];
}
if (![managedObjectContext save:&error])
{
// Handle the error.
}
NSLog(@"Save error: %@", error);
[fetchRequest release];
self.fetchedResultsController = nil;
[setsTableView reloadData];
}
-(IBAction)createSet
{
Set *set = (Set *)[NSEntityDescription insertNewObjectForEntityForName:@"Set" inManagedObjectContext:managedObjectContext];
set.weight = [NSNumber numberWithFloat:weightSelected2];
set.reps = [NSNumber numberWithInt:repSelected];
set.timeStamp = self.picker.date;
[self.exercise addSetsObject:set];
NSError *error = nil;
if (![managedObjectContext save:&error])
{
// Handle the error.
}
NSLog(@"error: %@", error);
self.fetchedResultsController = nil;
[setsTableView reloadData];
}
I'm trying to keep the new code not too different from this, maybe if I could just adjust a few things instead of creating something entirely new.
Edit:
Here is kinda what I have so far, a little stuck but still working on it. Thanks
//Session.h
@interface Session : NSManagedObject {
NSString * const kSessionLeavingActiveSession = @"kSessionLeavingActiveSession";
NSString * const kSessionChangingActiveSession = @"kSessionChangingActiveSession";
static Session *activeSession = nil;
//Session.h
@implementation Session
// a static method to retrieve & create if nil the active session
+ (Session *)activeSession {
if (activeSession = nil)
{
session = (Session *)[NSEntityDescription insertNewObjectForEntityForName:@"Session" inManagedObjectContext:managedObjectContext];
}
}
+ (Session *)sessionForDate:(NSDate *)date andSetActive:(BOOL)isActive {
NSCalendar *calendar = [NSCalendar currentCalendar];
unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *dateComponentsForToday = [calendar components:unitFlags fromDate:self.picker.date];
[dateComponentsForToday setHour:0];
[dateComponentsForToday setMinute:0];
[dateComponentsForToday setSecond:0];
NSDate *targetDateBegins = [calendar dateFromComponents:dateComponentsForToday];
NSDate *targetDateEnds = [targetDateBegins dateByAddingTimeInterval:(60 * 60 * 24 - 1)];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat: @"(timeStamp >= %@ && timeStamp <= %@)", targetDateBegins, targetDateEnds]];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Session" inManagedObjectContext:managedObjectContext]];
NSError *error = nil;
NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(@"Fetch error: %@", error);
if ([results count])
{
session = (Session *)[results objectAtIndex:0];
NSLog(@"Already have session for date: %@", session.timeStamp);
}
else
{
session = (Session *)[NSEntityDescription insertNewObjectForEntityForName:@"Session" inManagedObjectContext:managedObjectContext];
session.timeStamp = self.picker.date;
NSLog(@"New session for date: %@", session.timeStamp);
}
//send Notification kSessionChangingActiveSession if isActive == YES
//if isActive is true, set it to the active session.
}
+ (void)saveOrDestroyActiveSession {
//register this function as an observer on kSessionChangingActiveSession
//before the active session is changed, you will be able to determine
//if the session has anything associated with it, and persist it, or
//destroy it.
//determine if it has exercises assigned to it.
//if it does, save the context.
//if it doesn't destroy the active session and set activeSession to nil
}
+ (void)saveActiveSession {
//register this function as an observer on kSessionLeavingActiveSession.
//If you are leaving an area of the application where you are working on
//the session, you want to send this notification so that you can save
//the session if you have added exercises.
//you don't want to delete it though, if you can still go back to the
//active session, for example, if it's the active session view controller
//on a tab controller.
}
// the rest of your session methods
@end
//your app delegate
- (void)applicationWillResignActive:(UIApplication *)application {
//send a notification that you are leaving the active session
}
//viewController.m
//modify your fetched results controller to pull it's list of exercises from the
//active session, in case it's not saved you can still retrieve the exercises associated
//with it.
- (void)viewDidUnload {
//send a notification that you are leaving the active session
}
- (void)createSession {
Session *activeSession = [Session sessionForDate:self.picker.date andSetActive:YES];
NSSet *filteredExercisesFromSession=[session.exercises filteredSetUsingPredicate:[NSPredicate predicateWithFormat: @"name == %@",selectedExerciseName]];
if ([filteredExercisesFromSession count] > 0)
{
self.exercise=[filteredExercisesFromSession anyObject];
}
else
{
self.exercise = (Exercise *)[NSEntityDescription insertNewObjectForEntityForName:@"Exercise" inManagedObjectContext:managedObjectContext];
self.exercise.name = selectedExerciseName;
[session addExercisesObje开发者_如何学运维ct:exercise];
}
//if you've added exercises go ahead and save.
//if you haven't let the observers take care of persisting or destroying it.
}
This is probably a little dirtier than I would have liked to write it, but it should give you a good idea of my view on how to solve your problem.
//Session.m
//Check out the link to PSFoundation and the ActiveRecord Core Data methods
//https://github.com/steipete/PSFoundation/tree/master/activerecord-coredata
NSString * const kSessionLeavingActiveSession = @"kSessionLeavingActiveSession";
NSString * const kSessionChangingActiveSession = @"kSessionChangingActiveSession";
static Session *activeSession = nil;
@implementation Session
// ....
// a static method to retrieve & create if nil the active session
+ (Session *)activeSession {
//if activeSession = nil create a new instance
//reading the code it looks like you only create a new session if there
//isn't a session that already exists for the day chosen in the date picker?
//If that's the case, then it is only possible for there ever to be
//a single instance of an active session, one which is currently in view.
}
+ (Session *)sessionForDate:(NSDate *)date andSetActive:(BOOL)isActive {
//wrap all of your create session logic in here.
//search for a session that exists for this date, and return it if
//it exists, or create a new session if it doesn't.
//send Notification kSessionChangingActiveSession if isActive == YES
//if isActive is true, set it to the active session.
}
+ (void)saveOrDestroyActiveSession {
//register this function as an observer on kSessionChangingActiveSession
//before the active session is changed, you will be able to determine
//if the session has anything associated with it, and persist it, or
//destroy it.
//determine if it has exercises assigned to it.
//if it does, save the context.
//if it doesn't destroy the active session and set activeSession to nil
}
+ (void)saveActiveSession {
//register this function as an observer on kSessionLeavingActiveSession.
//If you are leaving an area of the application where you are working on
//the session, you want to send this notification so that you can save
//the session if you have added exercises.
//you don't want to delete it though, if you can still go back to the
//active session, for example, if it's the active session view controller
//on a tab controller.
}
// the rest of your session methods
@end
//your app delegate
- (void)applicationWillResignActive:(UIApplication *)application {
//send a notification that you are leaving the active session
}
//viewController.m
//modify your fetched results controller to pull it's list of exercises from the
//active session, in case it's not saved you can still retrieve the exercises associated
//with it.
- (void)viewDidUnload {
//send a notification that you are leaving the active session
}
- (void)createSession {
Session *activeSession = [Session sessionForDate:self.picker.date andSetActive:YES];
//code to add exercises to session
//if you've added exercises go ahead and save.
//if you haven't let the observers take care of persisting or destroying it.
}
精彩评论