-1

Working on a shopping store app. I've been going in circles for the past week and a half trying to figure out how to correctly do this. The problem lies in a UILabel that needs to be dynamically updated with text that corresponds to checked checkboxes. It also needs to know whether to apply selection when apply button has been tapped or return previous selection if customer decided to change their mind and not tap apply. This is where I'm running into issue.

I refer to 3 controllers as image 1, image 2 and image 3.

My model is a separate class that I pass copies of back and forth to keep selections made by users when they wish to refine a collection of clothing item results.

So for example the user taps the refine button in image 1

They are taken to image 2 where they decide what they want to refine results by

They are then taken to image 3 page where they make the selection

Where problems begin:

In short in image 3 a customer makes a selection and taps done, they are then taken back to image two where their selection is shown in a string separated by commas in a UILabel underneath the chosen refine by option e.g. Gender. If they are ok with their selection they tap apply and the refining is done and displayed like in image 1. A tick is also shown in the refine button to make the customer aware refining is active.

Now lets say a selection has already been made like in the images below and the customer goes back to image 3 to modify a selection. Let's say he unchecked "microsites". What should happen is when he goes back to image 2 the list underneath the refine by option should be updated.

This works fine but I'm actually updating the property that is updated when the apply button is tapped. So if the customer decides they don't want to refine anymore and don't click apply but the back button instead to take them to image 1 then I need the original selection string to be updated in the property.

The thing is this very property is updated whenever a selection is made in image 3. So when the customer does return to image 2 then because we unchecked "microsites" only "men" will show in the string underneath the refine by option.

I've tried creating a temp property to hold the previous selection but thing's just really get messy with all this going back and forth.

Further info:

I pass my model class back and forth between controllers using the prepareForSegue method and delegation/protocols.

Image 2 is aware when the done button in image 3 is tapped. This is where I pass the model over. Image 1 knows when the apply button in image 2 is tapped and again this is where I pass the model over. To pass the model from image 1 to 2 then 2 to 3 I use the prepareForSegue method.

Image 1:

enter image description here

Image 2:

enter image description here

Image 3:

enter image description here

How would you do this? I feel I've made a good start by moving all my model into its own class. This has made things easier but the other problem with the UILabel is holding me back.

Update:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{

    if ([[[sender titleLabel] text] isEqualToString:@"Gender"]) {

        VAGRefineGenderViewController *vc = [segue destinationViewController];

        [vc setDelegate:self];

        [vc setRefineModel:[self refineModel]];
    }
}

Working code:

@implementation VAGRefineModel
{
    VAGRefineModel *_object;
}

-(id)copyWithZone:(NSZone *)zone
{

    VAGRefineModel *modelCopy = [[VAGRefineModel alloc] init];
    modelCopy->_object = [_object copyWithZone: zone];
    return modelCopy;
}

Then in image 2/controller 2 I just set the model being passed to controller 3 as the copy of the existing model.

LondonGuy
  • 10,778
  • 11
  • 79
  • 151
  • What mechanism do you use to make vc2 aware that done was tapped in vc3? Delegates, blocks or other? – Paul.s May 21 '14 at 23:33
  • @Paul.s I use delegates. I pass the model instance into a method called didTapDoneButtonWithModel:. Then in controller 2 I call that method then set my model property to that instance. – LondonGuy May 21 '14 at 23:39
  • All you need to do is pass the proper addressability. – Hot Licks May 22 '14 at 01:10
  • A big thank you to who ever marked me down without explaining why. Thumbs up – LondonGuy May 22 '14 at 01:30

2 Answers2

1

This seems fairly simple.

  • You should indeed create a copy of the model and pass this to the next viewController then you don't have to worry about the edits made to it.
  • If the user presses back then that copy is just discarded.
  • If you press done then you receive the copy and replace your current model then reload your views.

It might look as simple as this (no error handling to make it easy to follow)

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
{
  Model *model = [self.model copy];

  VC2 *viewController = segue.destinationViewController;
  viewController.model    = model;
  viewController.delegate = self;
}

- (void)didTapDoneButtonWithModel:(Model *)model;
{
  self.model = model;
  [self reloadData];
}
Paul.s
  • 38,494
  • 5
  • 70
  • 88
  • Just added my prepareForSegue method for controller 2 to the question. So basically I need to pass an copy of the instance of the model to controller 3? – LondonGuy May 22 '14 at 00:06
  • For some reason I'm gettin -[VAGRefineModel copyWithZone:]: unrecognized selector sent to instance – LondonGuy May 22 '14 at 00:08
  • You will need to actually implement copying manually - see other posts for tips. e.g. http://stackoverflow.com/questions/1459598/how-to-copy-an-object-in-objective-c – Paul.s May 22 '14 at 00:09
  • Worked perfectly. I declared NSCopying in my model .h class and also implemented the copyWithZone method in my model class .m file. I've never had to use -> operator before but in this case I did. I've put the code above. – LondonGuy May 22 '14 at 01:11
0

I didn't read your post in detail, but did read enough to get the gist of it.

I'm gonna call your screen level 1 (master), level 2 (top level detail) and level 3 (fine detail) instead of image 1/2/3, because I'm talking about pictures, I'm talking about master/detail view controllers.

It sounds like you have 3 levels of view controllers that allow the user to edit finer levels of detail for a search.

I would suggest setting up your model so you can encapsulate the details handled by levels 2 and 3 into objects. When you get ready to drop to level 3, create a copy of the settings for gender and micro sites, and pass it to the level view controller. The user will interact with level 3, which has it's own copy of the settings.

Level 3 should set up level 2 as it's delegate, with a delegate message

-userChangedSettings: (Level3SettingsObject *) changedSettings

Or something similar.

If the clicks done, the level 3 VC would invoke that method on it's delegate, passing the changes to the Level3Settings object up to level 2, then pop itself/dismiss itself. (whichever is appropriate.)

If instead the user clicks cancel, just close pop/dismiss without calling the delegate method to tell the delegate about the change in settings. The settings in the level 2 object won't have changed.

The same would go for the communication between level 2 back up to level 1.

If it makes sense, you can make it so that the settings for level 1 contain level 2 data objects, and that the settings for level 2 contain level 3 data objects. That way changes to level 3 get passed back to level 2, and if the user cancels from level 2, all the changes made in level 2 and level 3 are discarded, and only if they tap save in level 2 do the changes from that level get passed up to level 1.

Duncan C
  • 128,072
  • 22
  • 173
  • 272