Search code examples
iosobjective-cios7core-graphics

UIGraphicsGetCurrentContext vs UIGraphicsBeginImageContext/UIGraphicsEndImageContext


I am new to these parts of iOS API and here are some questions that are causing an infinite loop in my mind

  1. Why does ..BeginImageContext have a size but ..GetCurrentContext does not have a size? If ..GetCurrentContext does not have a size, where does it draw? What are the bounds?

  2. Why did they have to have two contexts, one for image and one for general graphics? Isn't an image context already a graphic context? What was the reason for the separation (I am trying to know what I don't know)


Solution

  • UIGraphicsGetCurrentContext() returns a reference to the current graphics context. It doesn't create one. This is important to remember because if you view it in that light, you see that it doesn't need a size parameter because the current context is just the size the graphics context was created with.

    UIGraphicsBeginImageContext(aSize) is for creating graphics contexts at the UIKit level outside of UIView's drawRect: method.

    Here is where you would use them.

    If you had a subclass of UIView you could override its drawRect: method like so:

    - (void)drawRect:(CGRect)rect
    {
        //the graphics context was created for you by UIView
        //you can now perform your custom drawing below
    
        //this gets you the current graphic context
        CGContextRef ctx = UIGraphicsGetCurrentContext();
    
        //set the fill color to blue
        CGContextSetFillColorWithColor(ctx, [UIColor blueColor].CGColor);
    
        //fill your custom view with a blue rect
        CGContextFillRect(ctx, rect);
    }
    

    In this case, you didn't need to create the graphics context. It was created for you automatically and allows you to perform your custom drawing in the drawRect: method.

    Now, in another situation, you might want to perform some custom drawing outside of the drawRect: method. Here you would use UIGraphicsBeginImageContext(aSize)

    You could do something like this:

    UIBezierPath *circle = [UIBezierPath
                            bezierPathWithOvalInRect:CGRectMake(0, 0, 200, 200)];  
    
    UIGraphicsBeginImageContext(CGSizeMake(200, 200));
    
    //this gets the graphic context
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    //you can stroke and/or fill
    CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
    CGContextSetFillColorWithColor(context, [UIColor lightGrayColor].CGColor);
    [circle fill];
    [circle stroke];
    
    //now get the image from the context
    UIImage *bezierImage = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();
    
    UIImageView *bezierImageView = [[UIImageView alloc]initWithImage:bezierImage];
    

    I hope this helps to clear things up for you. Also, you should be using UIGraphicsBeginImageContextWithOptions(size, opaque, scale). For further explanation of custom drawing with graphics contexts, see my answer here