1

I feel silly again but I don't manage to navigate back and forth between the subviews of my project. I can add as many subviews as I want as long as it just goes forward, but as soon as I want to come back to one of the views previously visited I have a problem... here is my simplified code:

C4Workspace.h

#import "C4CanvasController.h"
#import "FirstView.h"
@interface C4WorkSpace : C4CanvasController{
    FirstView *firstView;
}
@end

C4Workspace.m

#import "C4Workspace.h"

@implementation C4WorkSpace

-(void)setup {
    firstView=[FirstView new];
    firstView.canvas.frame=CGRectMake(0, 0, self.canvas.width, self.canvas.height);
    firstView.canvas.userInteractionEnabled=YES;
    [firstView setup];
    firstView.mainCanvas=self.canvas;
    [self.canvas addSubview:firstView.canvas];
}

@end

FirstView.h

#import "C4CanvasController.h"
#import "SecondView.h"

@interface FirstView : C4CanvasController{
    C4Label *goToSecondView;
    SecondView *secondView;

}
@property (readwrite, strong) C4Window *mainCanvas;

@end

FirstView.m

#import "FirstView.h"
@implementation FirstView
-(void)setup{
    goToSecondView=[C4Label labelWithText:@"go to second View"];
    goToSecondView.origin=CGPointMake(20, 50);
    [self.canvas addLabel:goToSecondView];
    [self listenFor:@"touchesBegan" fromObject:goToSecondView andRunMethod:@"goToSecondView"];
}
-(void)goToSecondView{
    [goToSecondView removeFromSuperview];
    C4Log(@"second view");
    secondView=[SecondView new];
    secondView.canvas.frame=CGRectMake(0, 0, self.canvas.width, self.canvas.height);
    secondView.canvas.userInteractionEnabled=YES;
    [secondView setup];
    secondView.mainCanvas=self.canvas;
    [self.canvas addSubview:secondView.canvas];  
}
@end

SecondView.h

#import "C4CanvasController.h"
#import "FirstView.h"
@interface SecondView : C4CanvasController{
    C4Label *goToFirstView;
    FirstView *firstView;
}
@property (readwrite, strong) C4Window *mainCanvas;
@end

SecondView.m

#import "SecondView.h"
@implementation SecondView
-(void)setup{
    goToFirstView=[C4Label labelWithText:@"go to First View"];
    goToFirstView.origin=CGPointMake(20, 50);
    [self.canvas addLabel:goToFirstView];
    [self listenFor:@"touchesBegan" fromObject:goToFirstView andRunMethod:@"goToFirstView"];
}

-(void)goToFirstView{
    [goToFirstView removeFromSuperview];
    C4Log(@"first view");
    firstview=[FirstView new];
    firstview.canvas.frame=CGRectMake(0, 0, self.canvas.width, self.canvas.height);
    firstView.canvas.userInteractionEnabled=YES;
    [firstView setup];
    firstView.mainCanvas=self.canvas;
    [self.canvas addSubview:firstView.canvas];   
}
@end
suMi
  • 1,536
  • 1
  • 17
  • 30

1 Answers1

1

I think you're over complicating the procedure.

The "control" of which subview should be done by the containing view controller, so, if the two views are on the canvas then it should be the canvas that deals with the switching instead of the objects themselves.

Thing to help improve your approach:

  1. Get rid of references to the canvas from the subclasses.
  2. The views of your subclassed controllers all post touchesBegan notifications... Use these in the workspace i.e. [self listenFor:@"touchesBegan" fromObject:firstOrSecondView.canvas and runMethod:@"switch:"];
  3. Switch by either changing the zPosition or hiding / revealing the appropriate view...

I reduced your implementations to the following:

FirstView.m

#import "FirstView.h"
@implementation FirstView
-(void)setup{
    goToSecondView=[C4Label labelWithText:@"go to second View"];
    goToSecondView.origin=CGPointMake(20, 50);
    [self.canvas addLabel:goToSecondView];
    goToSecondView.userInteractionEnabled = NO;
}
@end

SecondView.m

#import "SecondView.h"
@implementation SecondView
-(void)setup{
    goToFirstView=[C4Label labelWithText:@"go to First View"];
    goToFirstView.origin=CGPointMake(20, 50);
    [self.canvas addLabel:goToFirstView];
    goToFirstView.userInteractionEnabled = NO;
}
@end

C4WorkSpace.m

#import "C4Workspace.h"
#import "FirstView.h"
#import "SecondView.h"

@implementation C4WorkSpace {
    FirstView *firstView;
    SecondView *secondView;
}

-(void)setup {
    firstView=[FirstView new];
    firstView.canvas.frame = self.canvas.frame;
    [firstView setup];
    firstView.canvas.userInteractionEnabled = YES;
    [self.canvas addSubview:firstView.canvas];

    secondView=[SecondView new];
    secondView.canvas.frame = self.canvas.frame;
    [secondView setup];
    secondView.canvas.userInteractionEnabled = YES;
    [self.canvas addSubview:secondView.canvas];

    secondView.canvas.hidden = YES;

    [self listenFor:@"touchesBegan"
        fromObjects:@[firstView.canvas, secondView.canvas]
       andRunMethod:@"switchView:"];
}

-(void)switchView:(NSNotification *)aNotification {
    C4View *v = (C4View *)aNotification.object;

    if([v isEqual:firstView.canvas]) {
        firstView.canvas.hidden = YES;
        secondView.canvas.hidden = NO;
    } else {
        firstView.canvas.hidden = NO;
        secondView.canvas.hidden = YES;
    }
}

@end

This should work for you in the case that your views need differing functionality, like FirstView will have significantly different internal functionality than SecondView... If they are the same then you should think about collapsing them into the same subclass.

C4 - Travis
  • 4,502
  • 4
  • 31
  • 56
  • yes, this works as such but now the user can tab anywhere on the screen and will get to the other view. I would need to access the exact element of the other canvas (as there are other interactions on that canvas happening) and switch the views then.If there is a way to do so, that approach would be much easier... – suMi Oct 24 '13 at 06:58
  • about the need of different views: I'm trying to rebuild a new version of this: http://vimeo.com/58437447. So I'm having quite some different views here. I think it makes it much easier to understand the different states of the app if they can be found in different files/views, right? – suMi Oct 24 '13 at 06:59
  • answering my questions myself now: ok. So I suppose posting Notifications between those views is the method if I want only a specific object in that view to change from one view to another...Don't know if it makes sense to share that code later. Maybe others run into similar problems? – suMi Oct 24 '13 at 07:31
  • but one more question: I am kind of worried about the performance of the app as I will have quite many different views. Maybe that relates to the comment about the different views above: does it make sense to have different views for all different states? This might be an issue of performance vs. code legibility... – suMi Oct 24 '13 at 07:34
  • Nice video! I have a better idea of what you're getting at now. – C4 - Travis Oct 24 '13 at 15:59
  • **re: whole canvas** I'm skeptical about an entire canvas for each image element that you're putting on the screen. In general, I would suggest one canvas for each "screen"... so the alphabet screen has a canvas, with a bunch of subclassed C4Images for letters on it each of which broadcasts a `touchesBegan`. But, to answer your q about how to get the specific element, I would create a property for your label in your `.h` file, then you can say `listenFor:@".." from:controller.canvas.label runMethod:@".."` – C4 - Travis Oct 24 '13 at 16:03
  • Yes, it makes sense if your app is structured in a more broken-down way. But, the overuse of controllers will make it confusing as well. Every visible object in C4 is a view itself, so I would suggest thinking about how to use individual controllers to control a set of views that all do a similar thing. – C4 - Travis Oct 24 '13 at 16:05
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/39931/discussion-between-c4-travis-and-sumi) – C4 - Travis Oct 24 '13 at 16:05