May 2010
8 posts
Day 54: Tedious Rounded Views
Last post I wrote about transparent windows. I concluded that you only needed to write your own content view to make the window in any shape you like. Let’s suppose we want to have a rounded view with a pointing arrow on one of the four sides. The code is a bit tedious but might be a nice example of doing graphics in code wherever possible:
First we want to know the area in the view that...
Day 53: Transparent windows
A question that seems to come up online from time to time is how to create a window in a special shape; rounded corners or with arrows sticking out on a side much like those popovers on the iPad. I use something similar in Sketch and here’s the basic outline of how to do it:
You start by subclassing NSWindow and overriding the initWith… method. You can also create it in code of course...
Day 52: changeKeys:inBlock:
If for some reason you’re writing your own getters and setters code, you want to comply to KVO and properly notify any observers of change using willChangeValueForKey: and didChangeValueForKey:. Now this is straightforward enough but starts to get really ugly if in one method you have to notify a change to several keys using first having lets say four willChangeValueForKey: and afterwards...
Day 51: KVO+Blocks
Today’s code is not mine, but I do find it incredibly useful. As readers of this blog will know by know, in 10.6 Apple introduced Blocks to Objective-C. I have given plenty examples in the past, but today’s is a favourite of mine.
Andy Matuschak released this code almost a year ago and it’s an incredibly handy way to do Key-Value-Observing (KVO) with Blocks instead of those ugly...
Day 50: Guest post 2, NSResponder goodies
Today’s post was submitted to me some time ago by Vadim Shpakovski from snippetsapp.com. My apologies that it has taken so long to post it, but I am grateful that he wanted to contribute here. So without further ado:
Snow Leopard brought a lot of new APIs that make cool things possible in just a few lines of code. For example, NSResponder class has got a new method named swipeWithEvent:....
Day 49: Tail follow-up
On Day 47 I posted a snippet with the -tail method and a question was asked in what situation I found this useful. I thought it’d be a nice opportunity to post an example of how I use -tail in Sketch.
This abbreviated snippet of code makes a boolean operation over multiple bezier paths. I already have the code to do an operation on two shapes and using it on more than two shapes is...
Day 48: Guest Post: NSUserDefaults
Today’s post is the first guest post to appear on 365Cocoa. This snippet was suggested by Pierre Bernard from houdah.com, many thanks to him for suggesting it. He has two tricks to share about NSUserDefaults:
Category on NSUserDefaults to send out KVO notifications. Needed on iPhone where there is no NSUserDefaultsController
Use of #define to create setters and getters
@implementation...
Day 47: Back from break: -tail
I’ve taken a little break for which I apologise; a combination of friends and family visiting and a short holiday. But we’re back.
I often find I need everything except the first item in an array. Instead of starting iterating a for loop at i=1, I wrote this:
- (NSArray *)tail
{
if ([self count] == 0)
return [NSArray array];
return [self objectsAtIndexes:[NSIndexSet...
April 2010
15 posts
Day 46: In mourning once again
Apple announced the dates for WWDC2010 today as most of you will know. One of the major disappointments for me is the lack of Apple Design Awards for mac applications.
I wrote about this on my company’s blog and instead of giving a code snippet today, I’m just going to link to this blog post: The center of the app universe
Day 45: trivial nsview programming in fact
I had promised to write about the different ways to do view drawing; one way to get the data to draw a view is to provide standard getters and setters for the object(s) the view should draw. This is however too trivial do write something sensible about I now see.
One tip I can mention is to mark the view dirty whenever you are setting a new object on thr vire because NSView won’t redraw...
Day 44: nsview programming
View programming is often considered difficult by programmers who have never actually done it. Let me tell you; it’s not. I’m not sure how this misunderstanding arose or why exactly it is perceived as difficult. Maybe just because it’s so unfamiliar and people don’t know where to start.
Just like with any programming project, stick to MVC and just use the view for the...
Day 43: NSView event handling 2; mouse coordinates
Intercepting mouse clicks is easy enough, you just have to override mouseDown:. However correctly getting the location of the cursor inside your view is less straightforward.
NSView has a bunch of method for converting points from one view/window’s coordinate system to another but I find them very confusingly named. I can never remember the one I need. I basically always end up...
Day 43: NSView event handling 1; mouseMoved
Custom view programming often involves two distinct kind of operations; drawing and event handling. I have already given a few examples of drawing stuff in NSViews and today I’ll start with some examples of handing events.
Mouse events enter your view in four different methods; mouseDown, mouseDragged, mouseUp and optionally mouseMoved. To accept mouseMoved events, you’ll have to tell...
Day 42: NSView convenience
For today I want to show a simple extension on NSView I find quite useful for constructing views in code, basically reducing three lines of code to one. View layout programming is always convoluted so the fewer lines we need, the better it is;
- (void)setFrameHeight:(float)height
{
NSSize s = [self frame].size;
s.height = height;
[self setFrameSize:s];
}
-...
Day 42: no code today
I forgot to post something yesterday I’m afraid, so it’ll just take me a bit longer to get to 365. Im sure this is a violation of my earlier claim but there it is.
Today I submitted SketchPad 1.1 for review and I wanted to share a little gotcha I stumbled upon. I had downloaded the iPhone OS 4 beta but of course selected the 3.2 SDK to build. I got a codesign warning (not an error)...
Day 41: createDirectoryIfNecessary:
Another shorthand (this time on NSFileManager) that’ll explain itself:
- (BOOL)createDirectoryIfNecessary:(NSString *)directory
{
BOOL isDir = NO;
if ([self fileExistsAtPath:directory isDirectory:&isDir] && isDir) return YES;
if ([self fileExistsAtPath:directory isDirectory:&isDir] && !isDir) return NO;
return [self createDirectoryAtPath:directory...
Day 40: isValidIndex:
I hate to check if an index I’m accessing in an array is valid; that is, it’s bigger than zero and smaller than the count. I know its essential but it doesn’t quite produce readable code, so once again, I create a category method that wraps it in easily understandable terms.
@implementation NSArray (NSArray_365Cocoa)
- (BOOL)isValidIndex:(NSUInteger)anIndex;
{
return anIndex...
Day 39: addObjectIfNotNil:
NSMutableArray throws an exception when you try to insert nil into an array. Often I find that I am retrieving possible objects from somewhere and I don’t want to convolute my code by checking for nil all the time or wrapping them in those ugly try-catch statements. So I do what I always do in cases like these:
@implementation NSMutableArray (NSArray_365Cocoa)
-...
Day 38: PNGRepresentationWithInterlaced
NSImage’s TIFFRepresentation is nice, but they are quite big. PNG’s are always smaller and that’s why I have this little category on NSImage:
- (NSData *)PNGRepresentationWithInterlaced:(BOOL)interlaced
{
NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:[self TIFFRepresentation]];
return [imageRep PNGRepresentationWithInterlaced:interlaced];
}
Day 37: NSResponder actions (5)
A few days ago I showed how I initialized all my actions, and keep in mind I stored all of them in a dictionary. Today I’ll go from toolbar actions to a full toolbar. We start with this dictionary of actions we already have but note that we probably have actions we don’t want in our toolbar. I gave action a -showInToolbar method that subclasses override, similarly there is an...
Day 36: -filterUsingBlock:
Today I’ll highlight a method on NSArray which I’ll be using in the next chapter on NSResponder action. It doesn’t need much further explanation but still I think it’s useful:
- (NSArray *)filterUsingBlock:(BOOL (^)(id object))block
{
return [self filteredArrayUsingPredicate:
[NSPredicate predicateWithBlock:
^(id evaluatedObject, NSDictionary *bindings) {
...
Day 35: NSResponder actions (4)
Today we’ll be actually creating our actions and inserting them in the responder chain. We keep a dictionary of all our actions in case we need to perform actions programatically and, as we’ll see tomorrow, for our toolbar.
The setup is done in a method named -createActions which finds a responder the views have in common and then does its thing. -actionClassNames returns an array...
Day 34: NSResponder actions (3)
Continuing the series, I’ll give an example of creating a toolbar item for an action. Again I am heavily relying on conventions with regards to action names and images. Keep in mind that all this stuff is in the base class and that subclasses can override any of the methods to customize behaviour. A good example of that is the -toolbar method that subclasses are supposed to override.
-...
March 2010
31 posts
Day 33: NSResponder actions (2)
In the first article I outlined the problem one faces; you can’t write your code in one view subclass because it won’t always be the first responder. You also can’t subclass the one responder all have in common (the window) since that’d be terrible coding practice. The solution is of course to inject something that handles these actions in the responder chain and instead of...
Day 32: NSMenuItem actions - Don't do it like this
Yesterday’s article reminded me of a clear mistake I made when I first started with Cocoa programming. The problem concerned connecting menu items to particular actions in my document. With a document-based application this was a problem since both were not in the same nib file. What I ended up doing was connecting them to my AppController in the MainMenu.nib and in the AppController...
Day 31: NSResponder actions
For 365Cocoa day three and four I’ve talked about NSClassFromString and its counterpart NSStringFromClass and noted how useful I find them and I gave a few examples. During the next few days I want to describe how in Sketch I handle toolbar and menu-item actions. These make heavy use of these dynamic functions and will demonstrate these functions in a broader context.
The first thing I have...
Day 30: a lazy day
As the title suggests, it’ll be a lazy day for 365Cocoa. I’m not even going to fully write out today’s episode - partly because its to simple. The thing is that I’ve spent all day with Sketch and my head it a bit dizzy with code. But a promise is a promise so there we are.
I find that quite often I’m putting integers and floats in dictionaries and I don’t like...
Day 29: -containsObjectOfClass:
Today I’ll be going back to the very beginning of 365Cocoa with a category on NSArray. I do find that I often need to see if an array contains objects of a certain class. One use is in validating menu and toolbar items for example; based on the layers you might have selected you want to enable/disable some items. This method takes perfect care of that:
-...
Day 28: C99
Another quick tip today. When I started with Objective-C it really bugged me that the compiler wouldn’t accept the following:
for (NSInteger i=0; ...)
but instead forced you to do:
NSInteger i;
for (i=0; ...)
I found out that the standard C doesn’t allow this but that the C99 dialect of the compiler does. You can set it by going to your target, open up the inspector, go to the build...
Day 27: toolbarHeight
The following snippet is taken from somewhere in Apple’s docs. It’s nice reminder for those who need to know the height of an NSToolbar:
- (float)toolbarHeight
{
NSToolbar *toolbar;
float toolbarHeight = 0.0;
NSRect windowFrame;
toolbar = [self toolbar];
if(toolbar && [toolbar isVisible]) {
windowFrame = [NSWindow contentRectForFrameRect:[self frame]
...
Day 26: Don't call it contentView
I’m putting the drawing series aside again, for a few days of short tips. Today’s is a bit obscure, but it has bit me a few times.
Dont call an instance variable in an NSBox subclass contentView. It’ll clash with another variable that is apparently already defined there. You’ll get no errors but just unexpected behaviour.
Day 25: Drawing: NSAffineTransform, part 2
Yesterday I gave a short explanation of how NSAffineTransform works and I’ll give some concrete examples today. We’ll be going to draw a rectangle like below. Note that its frame is in the center of the view.
- (void)drawRect:(NSRect)dirtyRect
{
NSSize size = [self bounds].size;
NSRect midRect = NSMakeRect((size.width-100)/2, (size.height-50)/2, 100, 50);
NSAffineTransform...
Day 24: Drawing: NSAffineTransform, part 1
Today we’ll continue our little drawing series with a short introdroduction to NSAffineTransform. This class is useful for either translating coordinates to a different coordinate space or - and this is more important - changing all future drawing for the current graphics context in a certain way.
By default, the 0,0-coordinate lies in the bottom left but you can move the origin around with...
Day 23: Core Data Migration Crash
There was this bug in Fontcase, related to Core Data which plagued me for a while a few months ago. The solution was quite obscure so I thought I’d share it here.
The problem arose if Fontcase was built on 10.6. If so, the CoreData migration manager would fail on 10.5 mysteriously. I searched in vain for a solution until <a...
Day 22: perceived launch time
performSelector:withObject:afterDelay: has many uses, but I think there’s one which is often overlooked - at least as far as I know.
Performance is often a matter of perception and delaying methods by 0.0 can be an excellent remedy without needing to spawn threads. For Fontcase and Sketch I’ve been wanting to improve performance and speeding up launch time is one of them. I found that...
Day 21: Lazy: NSZombieEnabled
I feel lazy today, so I’m going for a quick one; NSZombieEnabled. This environmental variable can be your saviour in times of memory issues. Whenever NSZombieEnabled is set, instead of just deallocating objects, they will be replaced by NSZombie objects which throw an exception whenever they are accessed, giving you nice stack trace as an alternative to an otherwise non-descriptive...
Day 20: -collapseAllGroups
Today I’ll take another break from the current drawing series and highlight something from ImageKit instead. As most of you’ll know, Apple introduced ImagKit in 10.5 and the most commonly used class is probably the IKImageBrowserView. It’s incredibly fast and very flexible but suffered from some nasty bugs in 10.5. For example, Apple had forgotten to implement a few important methods related to...
Day 19: +mainQueue & Blocks
Today I’ll take a little break from the drawing series. Yesterday I went to NSCoderNight in London (thanks to @abizern for starting this) and had a little chat with @mikeabdullah about blocks. I mentioned one snippet of code I use quite a lot and I thought it’d be nice to mention it here. It involves blocks again which makes in 10.6-only.
It often happens that I want to delay some action to the...
Day 18: Custom drawing (6) : -strokeInside
Using the articles from the past few days, we now have all the ingredients to (finally) make an Inner Stroke. Because we will use -addCllip: we have to save and restore the graphics context, otherwise any subsequent drawing after this will have the same clipping path set.
@implementation NSBezierPath (365Cocoa)
- (void)strokeInside
{
[NSGraphicsContext saveGraphicsState];
CGFloat oldWidth =...
Day 17: Custom drawing (5) : NSGraphicsContext
Yesterday (or to be honest, earlier today), I gave a quick introduction to NSBezierPath’s -addCllip: and I said I’d give an example of how to do an inner stroke. By default, NSBezierPath only does a stroke on the center. It’s important to note that the points in your path located between the pixels, not on the pixels. As a consequence, a 1px stroke can’t be drawn exactly...
Day 16: Custom drawing (5) : -addClip:
NSBezierPath is for more useful than for simply creating ovals or rectangles. You can construct your own shapes using -lineTo: and curveTo:. Don’t forget that when you build up a path, always start with a -moveTo:, otherwise you’ll get an exception. Drawing an NSBezierPath is like putting your pen on a piece of paper. Wherever you first put down the pen is the -moveTo: call. Then when...
Day 15: Custom drawing (4) : NSBezierPath
Yesterday we’ve seen a tiny bit of drawing code but for real drawing code you’ll most likely be using NSBezierPath or images. Today, a short introduction on the former. NSBezierPath draws bezier paths (stating the obvious), which are either straight lines or curves. These segments can be mixed at will creating almost any shape imaginable. Apart from that, NSBezierPath offers some...
Day 14: Custom drawing (3)
Yesterday I’ve talked a bit about view geometry and the day before about dirty rectangles. Today I’ll give an example that uses these concepts of dirty areas in a view and bounds. This should also clarify an issue that keeps coming up in forums and mailing lists; weird drawing artifacts when controls are overlapping the view. To demonstrate, we create a simple project; a window with...
Day 13: Custom drawing (2)
Yesterday I said I’d illustrate the idea of dirty rects, but on second thought I think it’s better to first talk about view geometry. As we all know, an NSView has a frame, which is it’s location inside a superview. The bounds of a view is its inner frame. It’s difficult to describe this, so I think and example is the easiest way. Say we have a view and its frame is...
Day 12: Custom drawing
Custom Drawing in Cocoa is often seen by programmers as something complicated while it’s really not. In fact it’s quite easy but it’s different from just writing algorithms. In the next few days I’ll give a few tips and hints about drawing in custom views in Cocoa. Today, some quick introduction to some basic concepts and no actual code.
You usually start your custom...
Day 11: insertObjectsFromArray:atIndex
Today’s one is a simple one since I’ve had a busy day and frankly have seen enough Cocoa for the day. Still this can be a handy method and it’s not provided by default in Cocoa. So there we go;
@implementation NSMutableArray (NSArray_365Cocoa)
- (void)insertObjectsFromArray:(NSArray *)array atIndex:(int)index
{
for (id obj in array)
[self insertObject:obj...
Day 10: -sortedArrayUsingKey
From time to time we need to sort things and having written code to do so a few times I noticed that quite often I’m sorting arrays by a certain key whether the array contains NSDictionary’s or not. Instead of messing around with NSSortDescriptor all the time I wrote yet another category-method:
@interface NSArray (NSArray_365Cocoa)
- (NSArray *)sortedArrayUsingKey:(NSString *)key
{
...
Day 9: -each:
In yesterday’s post I introduced the +drawImageWithSize:block: method and said I wasn’t reall happy with the name but couldn’t think of a better one. @uliwitness was kind enough suggest a better name for this method; drawToImageWithSize:usingBlock: and I think he’s right. He also pointed out a glaring omission to this site which is of course the fact that it’s...
Day 8: +drawImageWithSize:block:
I received some comments with regards to my post yesterday from people who didn’t like my approach. After a little conversation it turned out there was a misunderstanding about what these hooks were supposed to do. So let me clarify
When you need to extend your baseclass in some way, the most common approach is to subclass. The problem this introduces is called the ‘fragile base class...
Day 7: In a state of disappointment (and some...
365Cocoa.tumblr.com is in mourning today. Why? My severe disappointment about the delayed iPad launch outside US and the continuing uncertainty as to when the App store will open for native iPad apps. But there’s no way I can get around writing something today so even though my thoughts are elsewhere, here’s today’s entry:
Categories are one of my favorite language features in...