gesturec4

Gesture controls crash when calling methods on C4WorkSpace.m


I'm working with the C4 framework on a project and I'm having a bit of trouble with using the gesture controls and calling methods from C4WorkSpace.

I found this link that had to do with this problem but it didn't seem to stop my program from throwing an error.

A little background: I'm creating a custom button class that has 4 properties: UIColor, C4Shape and 2 floats (x/y position). I'm storing the custom button objects in an array and have this bit of code going to add a gesture to each button and add it to the canvas.

C4WorkSpace.m

        for (button in buttonArray){
        [button.shape addGesture:TAP name:@"tapGesture" action:@"tapped"];
        [self.canvas addShape:button.shape];
        [self listenFor:@"tapped" fromObject:button andRunMethod:@"doThis:"];
}

And I also have a function outside my '-(void)setup' that just prints a log message:

-(void)doThis:(NSNotification *)notification{
NSLog(@"notification test");
}

I have extended my C4Shape class with a category and when I call this method it works fine:

#import "C4Shape+myC4Shape.h"

@implementation C4Shape (myC4Shape)

-(void)printTest{
    NSLog(@"this is a print test");
}
@end

The error I'm getting gets thrown when I try and tap on a button, it says: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[C4Shape tapped]: unrecognized selector sent to instance 0x931e9c0'

I have my "action" set to 'tapped', but that's just something I made up. I know this usually calls a method inside the shape class, but I'm trying to call a method that isn't in the C4Shape class but on the main WorkSpace. I'm not sure what's causing this or what I'm doing wrong? Is there something specific I need to be writing in the 'action' part of the method?


Solution

  • this Obj-C stuff can be confusing at first. Hopefully this will help.

    I notice two things for you to change.

    The first is in regards to your TAP gesture. When you add this to your code you're actually telling the gesture to recognize a TAP and then run the tapped method. However, this method doesn't exist (hence the -[C4Shape tapped]: unrecognized selector sent to instance 0x931e9c0). You should have a method in your code called -(void)tapped{}; for this message to go away.

    The following code illustrates this:

    @implementation C4WorkSpace
    
    -(void)setup {
        [self addGesture:TAP name:@"tap" action:@"tapped"];
    }
    
    -(void)tapped {
        C4Log(@"tapped!");
    }
    
    @end
    

    Putting that into a shape is quite similar.

    Second, for the subclassing, C4Shape (and all other visual objects) inherit from C4Control so I would suggest that subclassing C4Control isn't the best approach. For creating your own custom button with a C4Shape I would subclass C4Shape directly.

    The above code would look exactly the same for a subclassed C4Shape except that if you created a MyShape subclass would have @implementation MyShape instead.

    Finally, you want to add a little broadcast message to your tap method so that the canvas can listen for it... All in all your .h and .m files for your subclass should look like this:

    .h

    #import "C4Shape.h"
    
    @interface MyShape : C4Shape
    
    @end
    

    .m

    #import "MyShape.h"
    
    @implementation MyShape
    
    -(void)setup {
        [self addGesture:TAP name:@"tap" action:@"tapped"];
    }
    
    -(void)tapped {
        [self postNotification:@"tapNotification"];
    }
    
    @end
    

    Finally, with those two files in your project you can add the following to your workspace:

    #import "C4WorkSpace.h"
    #import "MyShape.h"
    
    @implementation C4WorkSpace
    
    -(void)setup {
        MyShape *m = [[MyShape alloc] init];
        [m rect:CGRectMake(0, 0, 100, 100)];
        m.center = self.canvas.center;
        [self.canvas addShape:m];
    
        [self listenFor:@"tapNotification" fromObject:m andRunMethod:@"heardTap:"];
    }
    
    -(void)heardTap:(NSNotification *)aNotification {
        MyShape *notificationShape = (MyShape *)[aNotification object];
        C4Log(@"%4.2f,%4.2f",notificationShape.center.x,notificationShape.center.y);
        C4Log(@"%@",notificationShape.strokeColor);
    }
    
    @end
    

    Here's a link to a gist with the 3 files you'll need for this to run.

    Button Subclass with Canvas Listener

    PS thanks for giving C4 a try!


    Oh, and this is the output I get in Xcode's console when I tap on the square:

    [C4Log] 384.00,512.00
    [C4Log] UIDeviceRGBColorSpace 1 0.1 0.1 1
    

    This gives me the x and y coordinates, as well as the strokeColor of the "button" without having to add these as objects to the MyShape class (because they already exist in C4Shape).