2

The target: to use patterns images to draw in Quartz 2D. At the present moment:

const CGPatternCallbacks kPatternCallbacks = {0, routine, NULL};

void routine(void *info, CGContextRef contextRef) {

    UIImage *brushTexture = [UIImage imageNamed:@"PatternImage1"];

    CGContextDrawImage(contextRef, CGRectMake(0, 0, 50, 50), brushTexture.CGImage);
}

To use in:

    CGPatternRef strokePattern = CGPatternCreate(NULL,
                                                 CGRectMake(0, 0, 50, 50),
                                                 CGAffineTransformIdentity,
                                                 50, // horizontal spacing
                                                 50, // vertical spacing
                                                 kCGPatternTilingNoDistortion,
                                                 true,
                                                 &kPatternCallbacks);

All this stuff inside implementation class (ViewController.m). And perfect, I can draw a pattern image.

The problem: to change something inside C callback function dynamically, in example:

In "ViewController.h"

@interface ViewController : UIViewController {
    NSString *imageName;
}

@property (nonatomic, strong) NSString *imageName;

And in the implementation class (ViewController.m)

@synthesize imageName;

imageName = @"PatternImage1";

void routine(void *info, CGContextRef contextRef) {

    //UIImage *brushTexture = [UIImage imageNamed:@"PatternImage1"];

    //CGContextDrawImage(contextRef, CGRectMake(0, 0, 50, 50), brushTexture.CGImage);
    CGContextDrawImage(contextRef, CGRectMake(0, 0, 50, 50), imageName.CGImage);
}

And ERROR!!! -> Use of undeclared identifier 'imageName'

And I've already tried...

void routine(void *info, CGContextRef contextRef) {

    //NSString *imageName = CFBridgingRelease(info);     //<- not working

    //NSString *imageName = (__bridge NSString *)(info);  //<- not working

    NSString *imageName = (__bridge NSString *) info;     //<- not working


    //UIImage *brushTexture = [UIImage imageNamed:@"PatternImage1"];

    CGContextDrawImage(contextRef, CGRectMake(0, 0, 50, 50), imageName.CGImage);
}

The routine structure can not change because it is defined by CGPatternCallbacks.

void routine(void *info, CGContextRef contextRef) { }

I searched a lot but have not found the solution. Topics like:

  • "Pass an Objective-C object to C function"

  • "Mix Objective-C and C"

  • "Callback function"

  • "C Callbacks"

Nothing, nothing and nothing.

Impossible? I do not think so! I will have to abandon... F***!

2
  • You are trying to access an instance variable of your class from a C function - that's not possible. Just a suggestion - use a global variable and set it to point to your view controller before invoking CGPatternCreate. That way you'll be able to access the property in the callback (ex. - controller.imageName.CGImage). Commented Jun 18, 2014 at 16:03
  • Thank you. I found it. I used the sentence: -> static NSString *imageName = @"PatternImage1"; <- And now, I can change the pattern image dynamically. Commented Jun 18, 2014 at 17:44

2 Answers 2

2

The info parameter the gets passed to your callback is whatever value you passed as the info parameter in your call to CGPatternCreate(). In Objective-C code, you would typically pass (__bridge void*)self. Then, in your callback, you'd cast it back to the appropriate type and call a method to do the real work:

void routine(void *info, CGContextRef contextRef) {
    ViewController* self = (__bridge ViewController*)info;
    [self drawPattern:contextRef];
}

- (void) drawPattern:(CGContextRef)contextRef {
    UIImage *brushTexture = [UIImage imageNamed:imageName]; // <- imageName can be an ivar
    CGContextDrawImage(contextRef, CGRectMake(0, 0, 50, 50), brushTexture.CGImage);
}

In your very simple case where you just want to pass an image name string in, you could pass that NSString* as the info pointer, instead. Or even the UIImage* created from the name so you don't have to create it each time. That avoids the need to call a method on the recovered self. However, it is very common to have more complicated needs, even if your needs right now are simple, so it's often worth the trouble to pass in self.

Sign up to request clarification or add additional context in comments.

3 Comments

I appreciate your comments very much. I did not know the syntax to call a method in Objective-C "- (void)" inside Callback Function, and could not find it searching forums. I will use your proposal to avoid creating NSObjects repeatedly in each function call. Because of course, my project makes more operations, such as changing the colour of the pattern.
Sorry, but I tried the alternative you propose, but does NOT WORK. Now I can not draw using the selected pattern image.
I made a copy/paste of the code. But it is possible that my application has some peculiarity: perhaps this fact alter the result. My App is an application to draw (with Quartz2D) and I use the method: - (void) touchesMoved.
0

Found it !!!

Found iiiiiiiit !!!

static NSString *imageName = @"PatternImage1";

It is visible inside callback function !!!!

Yabba Dabba Doo !!!

Complete source code. Only in "ViewController.m" :

#import "ViewController.h"

@implementation ViewController

static NSString *imageName = @"PatternImage1";

In some part of code:

const CGPatternCallbacks kPatternCallbacks = {0, routine, NULL};

In some part of code:

CGPatternRef strokePattern = CGPatternCreate(NULL, CGRectMake(0,0,50,50),
                                                 CGAffineTransformIdentity,
                                                 50, 50,
                                                 kCGPatternTilingNoDistortion,
                                                 true,
                                                 &kPatternCallbacks);

In some part of code, an "if/else" statement:

if () {
  imageName = @"PatternImage2";

} else if () {
  imageName = @"PatternImage3";

} else {
  imageName = @"PatternImage4";
}

And finally, the callback function:

void routine(void *info, CGContextRef contextRef) {

    UIImage *brushTexture = [UIImage imageNamed:imageName];

    CGContextDrawImage(contextRef, CGRectMake(0, 0, 50, 50), brushTexture.CGImage);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.