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.
Because of this, we know that for this occasion:
Moving on to transformations. Again, there are two separate classes, NSAffineTransform for Cocoa, and CGAffineTransform for CoreGraphics. Here’s some code:
Peace
-Joe
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

August 19th, 2007 at 4:02 pm
nice cgrect example
September 16th, 2007 at 9:22 am
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.
October 28th, 2007 at 3:16 am
if (CGRectIntersection(ballRect, paddleRect)!=CGRectIsNull) { //collision code
this code should be ==> if(CGRectIsNull(CGRectIntersection(ballRect, paddleRect))) {
October 28th, 2007 at 3:43 am
Oh! I mean, if(!CGRectIsNull(…
March 11th, 2008 at 8:23 pm
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 ); }
April 10th, 2008 at 9:57 am
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.
September 1st, 2008 at 8:05 am
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?
September 1st, 2008 at 6:32 pm
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).
September 2nd, 2008 at 9:04 am
ok thanks anyway. I lear anyway a lot from your blog. thanks
September 24th, 2008 at 7:34 pm
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.
October 19th, 2008 at 10:18 pm
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.
October 20th, 2008 at 2:12 am
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.
October 29th, 2008 at 5:45 pm
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
November 16th, 2008 at 11:47 am
UIColor is close to NSColor so you don’t need to go through a whole context setup.
December 2nd, 2008 at 11:34 pm
[…] 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で定義されているこれらを使うことになれる必要が有るでしょう。 […]
January 21st, 2009 at 3:01 am
Hey nice insight
I have bookmarked your post at http://www.iphonekicks.com/cocoa/UIKit_CoreGraphics_vs_AppKit_Cocoa
June 18th, 2009 at 5:25 am
CGAffineTransform *cgAffineTransform = [[CGAffineTransformMakeTranslation(x, y)] retain];
is it possible?????