UIKit/CoreGraphics vs. AppKit/Cocoa

The iPhone compiler, unfortunately, does not include any of the Cocoa/AppKit UI-oriented classes. This means your stuck with (sigh) CoreGraphics, or the CG- prefix, and the iPhone-specific UIKit with the UI- prefix, rather than the NS- (AppKit/Cocoa) classes you used to know and love. Listed below are some examples of these difference. We will begin with the rectangle structs.
NSRect nsRect = NSMakeRect(0.0f, 0.0f, 10.0f, 10.0f);
Whereas the equivalent in CoreGraphics:
CGRect cgRect = CGRectMake(0.0f, 0.0f, 10.0f, 10.0f);
By the way, nsRect and cgRect are the exact same internally. That is, the origin is defined as the bottom left corner (considering you didn’t change the coordinate plane), and the other 2 initializing components specify width and height from this point.

Because of this, we know that for this occasion:
nsRect.origin.x = cgRect.origin.x; nsRect.origin.y = cgRect.origin.y; nsRect.size.width = cgRect.size.width; nsRect.size.height = cgRect.size.height;
Almost the exact same pattern is shared by the Point structs. Look at NSPoint:
NSPoint nsPoint = NSMakePoint(0.0f, 0.0f)
And in CoreGraphics:
CGPoint cgPoint = CGPointMake(0.0f, 0.0f)
And, just as above, CGPoint and NSPoint are the exact same internally. They just have different constructor methods (NSMakePoint vs. CGPointMake) to confuse us all.

Moving on to transformations. Again, there are two separate classes, NSAffineTransform for Cocoa, and CGAffineTransform for CoreGraphics. Here’s some code:
NSAffineTransform *nsAffineTransform = [[NSAffineTransform transform] retain]; [nsAffineTransform translateXBy:x yBy:y];
Whereas in CoreGraphics, it is a bit simpler. You can initialize the transformation as a specific type:
CGAffineTransform *cgAffineTransform = [[CGAffineTransformMakeTranslation(x, y)] retain];
Now finally the most confusing, and IMHO, pesky, of all: the color classes. Defining and setting a color with AppKit was easy, especially if it was a standard color. All you had to do was:
- (void)drawRect:(NSRect) rect { [[NSColor whiteColor] set]; NSRectFill(rect);
Now, however, you have to get the application’s CGContextRef, create a ColorSpace and a float array containing Red, Green, Blue, and Alpha values 0.0f-1.0f, and then, and only then, can you create your color. Let’s take a look:
- (void)drawRect:(CGRect)rect { CGContextRef context = [[CGContextRef UICurrentContext] retain]; float blackArray[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGColor blackColor = CGColorCreate(colorSpace, blackArray); CGContextSetFillColorWithColor( context, blackColor ); CGContextFillRect( context, rect ); GBColorSpaceRelease(genericRGBSpace); [context release]; }
One final class: NSBezierPath. Unfortunately (or maybe fortunately), there is no CGBezierPath. Rather, you use UIBezierPath found in UIKit. There are a few differences, however. Let’s look at defining and using an NSBezierPath from the coordinates found in ‘ballRect’, along with another NSBezierPath from the coordinates found in ‘paddleRect’ to test for hit collision:
NSBezierPath *ballPath = [[NSBezierPath bezierPathWithRect:ballRect] retain]; NSBezierPath *paddlePath = [[NSBezierPath bezierPathWithRect:paddleRect] retain];
Whereas the equivalent class from UIKit:
UIBezierPath *ballPath = [[UIBezierPath bezierPath] appendBezierPathWithRect:ballRect]; [ballPath retain]; UIBezierPath *paddlePath = [[UIBezierPath bezierPath] appendBezierPathWithRect:paddleRect]; [paddlePath retain];
Unfortunately, UIBezierPath not only requires an extra method to initialize, but also is not quite as flexible. Let’s say you wanted to do a simple hit detection method. With AppKit, you just need to:
if ([paddlePath containsPoint:NSMakePoint(ballPath.origin.x, ballPath.origin.y)]) //collision code
UIBezierPath has no equivalent method. Luckily, there is a work around that does not involve using UIBezierPath’s at all, and rather just takes in the CGRect’s:
if (CGRectIntersection(ballRect, paddleRect)!=CGRectIsNull) { //collision code
And there you have it: an easy to use reference chart for drawing to your UIView subclass. This should make things much easier for a few people out there. Anyways, this has taken long enough, time to get back to whatever it is I do.

Peace
-Joe

17 Responses to “UIKit/CoreGraphics vs. AppKit/Cocoa”

  1. mmmi Says:

    nice cgrect example

  2. Daniel Says:

    I couldn’t understand some parts of this article o.us poetry, but I guess I just need to check some more resources regarding this, because it sounds interesting.

  3. Idiel Says:

    if (CGRectIntersection(ballRect, paddleRect)!=CGRectIsNull) { //collision code

    this code should be ==> if(CGRectIsNull(CGRectIntersection(ballRect, paddleRect))) {

  4. Idiel Says:

    Oh! I mean, if(!CGRectIsNull(…

  5. Zack Green Says:

    I got this to work. Much less complicated:

    -(void) drawRect:(CGRect)rect { CGRect greenRect = CGRectMake (0, 200, 320, 100); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBFillColor( context, 0.0, 1.0, 0.0, 1.0 ); CGContextFillRect( context, greenRect ); }

  6. Mack Says:

    Can I use NSSpeechSynthesizer on the iPhone? I don’t see a CGSpeechSynthesizer.

    If so, how would I inlcude that framework? I’m a Cocoa newb, so hand holding is appreciated. Basically I just did a little “I speak hello world.” on OS X and would like to do the same on iPhone OS.

    Thanks.

  7. Matax Says:

    UIBezierPath doesn’t exist. I’m trying to write a pong clone for iphone. I have seen that you make it for mac can you write a iphone (UIKit+CoreGraphic) tutorial about pong?

  8. admin Says:

    Matax,

    UIBezierPath does exist, but not in the iPhone SDK. It existed in a class-dump of the headers for the toolchain (jailbroken development). Unfortunately I can’t post any SDK specific code or tutorials until Apple takes down their NDA (the agreement every developer is forced into if he wants to release his apps on the itunes app store).

  9. Matax Says:

    ok thanks anyway. I lear anyway a lot from your blog. thanks

  10. Helder da Rocha Says:

    Bezier paths in CG are called simply ‘curves’. You can create bezier paths in CG using CGContextAddCurveToPoint (two control points) and CGContextAddQuadCurveToPoint (one control point) functions. They are used inside a path, so you should use those functions after a CGContextBeginPath(context) call. They are also relative to a ‘current point’, so you need at least an CGContextMoveToPoint(context, x0, y0) if you start the path with it.

    Using CGContextAddQuadCurveToPoint you obtain the same effect like this:

    CGContextMoveToPoint( context, ballRect.origin.x, // start pt ballRect.origin.y);

    CGContextAddQuadCurveToPoint( context, ballRect.origin.x + ballRect.size.width, // ctrl pt ballRect.origin.y + ballRect.size.height / 2, ballRect.origin.x + ballRect.size.height, // end pt ballRect.origin.x);

    (I may have missed something or confused clockwise with counter-clockwise, but something like this should work). Don’t forget to CGContextStrokePath() or you’ll see nothing.

  11. diiippp Says:

    I am using CGContextRef context = UIGraphicsGetCurrentContext();

    to get current context, but context variable is not getting initialized. So i am not able to display lines. I have included CoreGraphics.framework.

  12. diiippp Says:

    sorry i didn’t explain that it happens when i add new view in nib file and when i try to get current context of newly added view.

  13. admin Says:

    dip: are you waiting until awakeFromNib has been called? It may cause some issues if you haven’t. Also remember that this code is a bit outdated-it was written for the 1.1 toolchain iirc. The SDK and toolchain on 2.0 are completely different

  14. Scott Says:

    UIColor is close to NSColor so you don’t need to go through a whole context setup.

  15. CGValueはないけれどNSValueが使えます | iPhoneアプリ開発ブログ Says:

    […] CGValueはないけれどNSValueが使えます 2008 年 12 月 3 日 by 田中 CGRectやCGPointといったCoreGraphicsで定義された構造体をNSArrayなどに入れる場合、直感的にはCGValueというラッパが有りそうな気がします。しかし、実際にはCGValueというクラスは存在しません。調べてみるとAppleのDeveloperForums(英語)でズバリWrapper for CGRect?というトピックを発見しました。このトピックでのやり取りを要約すると、CGRectやCGPointでもNSValueが使えるということでした。どうやら回答者もこの質問を受けて初めて存在に気がついたようです。このことを調べていて知ったのですが、CocoaにはCGRectやCGPointと同等のNSRectやNSPointといったクラスが有るそうです。ただし、これはMac OS X(App Kit)のお話でiPhoneアプリには関係ないみたいです。逆に言うとApp Kitでの開発になれた人はCoreGraphicsで定義されているこれらを使うことになれる必要が有るでしょう。 […]

  16. Raj Says:

    Hey nice insight :-) I have bookmarked your post at http://www.iphonekicks.com/cocoa/UIKit_CoreGraphics_vs_AppKit_Cocoa

  17. user Says:

    CGAffineTransform *cgAffineTransform = [[CGAffineTransformMakeTranslation(x, y)] retain];

    is it possible?????

Leave a Reply

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word