1

Hei,

just starting to get into C4 and so far my experience has been great. I'm replicating the taking a photo with the camera-example at the moment and for some reason when I do everything as described in the tutorial (http://www.c4ios.com/tutorials/takingSnapshots) I get the following mistake: "No visible @interface for 'TakePhoto' declares the selector 'listenFor:from Object:'" (Take Photo is the file I'm working in) I think I have to declare "imageWasCaptured" in the class definition but I don't know as what? Any suggestions?

updated: here is the code https://github.com/susemiessner/Urban-Alphabets/tree/master/urbanAlphabets or just plain copied TakePhoto.h

#import "C4CanvasController.h"

@interface TakePhoto : C4CanvasController

@end

TakePhoto.m

    #import "TakePhoto.h"
    #define NavBarHeight 42
    #define TopBarFromTop 20

    @interface TakePhoto ()

    @end

    @implementation TakePhoto {
        //common variables
        UIColor *navBarColor;
        UIColor *buttonColor;
        UIColor *typeColor;

        //top toolbar
        C4Shape *topNavBar;
        C4Font *fatFont;
        C4Label *takePhoto;



        //camera
        C4Camera *cam;

        //bottom Toolbar
        C4Shape *bottomNavBar;
        C4Button *takePhotoButton;
    }
    -(void) setup{
        navBarColor=[UIColor colorWithRed:0.96875 green:0.96875 blue:0.96875 alpha:1];
        buttonColor= [UIColor colorWithRed:0.8984275 green:0.8984275 blue:0.8984275 alpha:1];
        typeColor=[UIColor colorWithRed:0.19921875 green:0.19921875 blue:0.19921875 alpha:1];

        [self topBarSetup];
        [self bottomBarSetup];
        [self cameraSetup];

    }
    -(void)topBarSetup{
        topNavBar=[C4Shape rect:CGRectMake(0, TopBarFromTop, self.canvas.width, NavBarHeight)];
        topNavBar.fillColor=navBarColor;
        topNavBar.lineWidth=0;
        [self.canvas addShape:topNavBar];


        fatFont=[C4Font fontWithName:@"HelveticaNeue-Bold" size:17];
        takePhoto = [C4Label labelWithText:@"Take Photo" font:fatFont];
        takePhoto.center=topNavBar.center;
        [self.canvas addLabel:takePhoto];}

    -(void)cameraSetup{
        cam = [C4Camera cameraWithFrame:CGRectMake(0,TopBarFromTop+NavBarHeight, self.canvas.width, self.canvas.height-(2*NavBarHeight+TopBarFromTop))];
        [self.canvas addCamera:cam];
        [cam initCapture];
        //tapping to take image
        [self addGesture:TAP name:@"capture" action:@"capturedImage"];
        [self numberOfTouchesRequired:1 forGesture:@"capture"];
//the following line is where I get the error
        [self listenFor:@"imageWasCaptured" fromObject:@"putCapturedImageOnCanvas"];
    }
    -(void) bottomBarSetup{
        bottomNavBar=[C4Shape rect:CGRectMake(0, self.canvas.height-(NavBarHeight), self.canvas.width, NavBarHeight)];
        bottomNavBar.fillColor= navBarColor;
        bottomNavBar.lineWidth=0;
        [self.canvas addShape:bottomNavBar];

        takePhotoButton=[UIButton buttonWithType: ROUNDEDRECT];
        [takePhotoButton setTitle:@"TakePhoto" forState:UIControlStateNormal];
        takePhotoButton.frame=CGRectMake(self.canvas.width/2-50, self.canvas.height-(NavBarHeight), 100, NavBarHeight);
        takePhotoButton.backgroundColor=buttonColor;
        takePhotoButton.tintColor=typeColor;
        [self.canvas addSubview:takePhotoButton];

    }

    -(void) takingPhoto{
        [cam captureImage];
    }
    -(void) captureImage{
        [cam captureImage];
    }
    -(void)putCapturedImageOnCanvas{
        C4Image *img = cam.capturedImage;
        img.width=240;
        img.center=CGPointMake(self.canvas.width*2/3, self.canvas.center.y);

    }


    @end
suMi
  • 1,536
  • 1
  • 17
  • 30

1 Answers1

1

To get your concept working there are a couple of holes in your approach that will prevent you from seeing anything actually happen. Your question is definitely one of them.

To answer your question:

listenFor:fromObject: is unrecognized because it actually doesn't exist.

The intention of listenFor methods is so that your app, or a specific object, can react to a notification or an action happening somewhere else in the application. So what you want to do is run a method when something happens.

Your method should be:

[self listenFor:@"imageWasCaptured" fromObject:cam andRunMethod:@"methodName"];

You want to listen for when the camera has finished capturing and then do something with that...


Other things I noticed...

If you want to use a C4Button, then the following:

takePhotoButton=[UIButton buttonWithType: ROUNDEDRECT];
[takePhotoButton setTitle:@"TakePhoto" forState:UIControlStateNormal];

Should be:

takePhotoButton = [C4Button buttonWithType:ROUNDEDRECT];
[takePhotoButton setTitle:@"TakePhoto" forState:NORMAL];

Also, you're subclassing C4CanvasController. To get your TakePhoto object's view onto the main canvas you need to create it properly.

To do this in the main canvas I wrote the following in my workspace:

#import "C4Workspace.h"
#import "TakePhoto.h"

@implementation C4WorkSpace {
    TakePhoto *tp;
}

-(void)setup {
    tp = [TakePhoto new];
    tp.canvas.frame = CGRectMake(30,
                                 30,
                                 self.canvas.width - 60,
                                 self.canvas.height - 60);
    tp.canvas.shadowOffset = CGSizeMake(10,10);
    tp.canvas.shadowOpacity = 1.0f;
    tp.canvas.userInteractionEnabled = YES;
    [tp setup];
    tp.mainCanvas = self.canvas;
    [self.canvas addSubview:tp.canvas];
}
@end

And, finally, to get your camera's image onto the main canvas, I had do bridge a little. I created a property in TakePhoto that lets me set the main canvas in your new controller. You'll notice in the code above the line that states tp.mainCanvas = self.canvas...

The TakePhoto header now looks like:

#import "C4CanvasController.h"

@interface TakePhoto : C4CanvasController
@property (readwrite, strong) C4Window *mainCanvas;
@end

And the putImageOnCanvas method now looks like:

-(void)putCapturedImageOnCanvas{
    C4Image *img = cam.capturedImage;
    img.width=240;
//    img.center=CGPointMake(self.canvas.width*2/3, self.canvas.center.y);
    img.center = CGPointMake([C4Math randomInt:self.mainCanvas.width], [C4Math randomInt:self.mainCanvas.height]);
    [self.mainCanvas addImage:img];
    [self.mainCanvas bringSubviewToFront:self.canvas];
}

The last two lines put the image on the canvas and then make sure that the TakePhoto canvas (i.e. the one with the camera) is brought to the foreground so the newly added image doesn't occlude it.

Because you're using a subclass of a C4CanvasController your app structure looks like:

C4WorkSpace.canvas > TakePhoto.canvas > Camera

C4 - Travis
  • 4,502
  • 4
  • 31
  • 56
  • sorry but I'm still confused here now. I tried to just run the camera example seperately without anything else. The code is on GitHub https://github.com/susemiessner/Urban-Alphabets/tree/master/cameraTest it still gives me an uncaught error. From what I understand in this `[self listenFor:@"imageWasCaptured" fromObject:cam andRunMethod:@"methodName"];` some other function/method has to return `imageWasCaptured`, or? (Sorry for being so not understanding!!!) – suMi Oct 18 '13 at 09:10
  • also I don't really get why you are suggesting adding the subviews differently from the tutorial on subviews. Could you explain that maybe? – suMi Oct 18 '13 at 09:20
  • **re: error** I will have a look at your project as soon as I can. There may be a couple of different reasons. First, you can't run camera apps on anything other than a device (i.e. iPhone or iPod) because the simulator can't simulate the camera. If you're using a device then there's something else going on. Right now I don't have a device at home but can check on monday for sure. – C4 - Travis Oct 19 '13 at 21:42
  • **re: imageWasCaptured** Yes, I can understand why this may be confusing. In a nutshell, the canvas to which you add a camera will run its own `imageWasCaptured` method. There is actually a semi-complicated setup that happens in the `addCamera:` method. Have a look at **line 50** in `C4CanvasController.m`... The confusion might come from 2 places. 1) `imageWasCaptured` is BOTH a method AND a NOTIFICATION 2) This is an API/Language issue that is probably the cause of your confusion (I will have a look at it) – C4 - Travis Oct 19 '13 at 22:02
  • **re: subviews** I am suggesting a different way of working with subviews because you've chosen to create the `TakePhoto` class as a subclass of `C4CanvasController`... But the controller (i.e. the `TakePhoto` object) is *not* a view, instead it *controls* a subview. So, there's an extra object in the mix. The camera object itself is a view and is added to the canvas of the `TakePhoto` controller. That's why you get `canvas > canvas > camera`... – C4 - Travis Oct 19 '13 at 22:06
  • p.s. these are all great questions. – C4 - Travis Oct 19 '13 at 22:07
  • thanks! that all makes sense. **re:error** yes, I am running it on a device. It's an iPhone 5 (running iOS7) and I'm building my projects in XCode 5. I can maybe try testing it on a 4th Generation iPodTouch tomorrow and see if that helps.... **re subviews and imageWasCaptured** thanks for the explanation! that totally does make sense to me! I'm just in the beginning of a bigger project and can also still change how to handle the different views, so if you suggest one way as better than the other let me know! – suMi Oct 20 '13 at 11:07
  • Using a 4 / iPod touch shouldn't make a difference. I'll have a look in the morning. – C4 - Travis Oct 20 '13 at 18:49
  • Had a look at the "error", and have found that you were using an extra **`:`** in your `[self addGesture:TAP name:@"capture" action:@"captureImage:"];` it should be `@"captureImage"` and not `@"captureImage:"` because the method you declared in your `TakePhoto.h` **doesn't** take a variable. – C4 - Travis Oct 21 '13 at 17:19
  • amazing! no more app crashing! BIG THANKS! – suMi Oct 21 '13 at 19:32
  • No prob. I'm happy you're using C4, so anything I can do to help please ask away! P.S. please feel free to accept the answer. – C4 - Travis Oct 21 '13 at 20:55