Recipe #2: Initializing user preferences using NSUserDefaults
Jan2
Recently I was in need of some user preferences. I read a guide on user defaults programming. Everything seemed easy and clear, but I still couldn’t find the thing that interested me most – initializing user preferences. By “initialization” I mean set defaults once so they can be overridden by user and not set again. For some reason I thought that I’d have to check each preferences key for its existence and set it accordingly.
Then the light bulb lit above my spiky head. I present you with the solution:
// Place this code into your apps delegate class + (void)initialize { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; // initialize the dictionary with default values NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:@"fooValue", @"fooKey", @"barValue", @"barKey", nil]; // and set them appropriately [defaults registerDefaults:appDefaults]; }
Now for refactored and more comfortable version you should use a separate plist for initializing user defaults. I believe it’s easier to add a row to plist file than add key/value pair into dictionary:
+ (void)initialize { // get the filename for "default defaults" NSString *defaultsFilename = [[NSBundle mainBundle] pathForResource:@"Defaults" ofType:@"plist"]; // initialize a dictionary with contents of it NSDictionary *defaults = [NSDictionary dictionaryWithContentsOfFile:defaultsFilename]; // register the stuff [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; }
The advantage of this approach is that even after updates to your app even unset defaults will be initialized (in case of newly added preferences).
That’s it! Kudos goes to Laurent Etiemble and Johan Kool for their answers to my question.
XCode file template for custom NSWindow subclass
Dec0
This has been for a while now in my drafts and I wanted to polish it so it wouldn’t require as much editing as some previous tutorials. I hope you’ll enjoy reading this one as much as I enjoyed writing this. I present you – custom NSWindow template tutorial.
From time to time while programming you’ll have to draw custom window. If it’s more often than “from time to time” you’ll find yourself writing the same code again and again. Of course it’s easy to extract repetitive code into separate class and include that class in every project (or few times into the same project), but this still not the prettiest solution. Im suggesting you an approach that exploits XCode’s customization – template for custom class that you’ll be able to include into your projects anytime you need it. In this case – it’s custom NSWindow subclass.
So here’s how we’re going to achieve this:
- Create project in XCode where we will code a template for custom NSWindow. If you are really good with Objective C – you can code our custom class in any text editor (TextEdit, TextMate) or in an IDE of your choice.
- Create custom NSWindow class
- Replace hardcoded constants (class names) with identifiers
- Move created class files to a location where XCode can consider them as being custom template files
git for everyone!!!111!!ONE
Dec0
I’ve found really nifty site today for dealing with git source control management system. It’s git ready. I think I may be one of the last ones to find it, cause it has loads of articles on different topics. You should definitely check it out if you haven’t yet.
Quickly change desktop background pt. 2
Nov1
Few weeks ago I wrote about writing an App for quickly changing background for Mac OS X desktop.
Things that’ve changed:
- Up to 10 items in history list (suggestion from Perspx).
- App is UI agent now (pseudo-background app). Activates via ⌘+⌥+⌃+B.
To download click this link: Change Background 0.0.2
Switch between header and implementation files
Nov0
In addition to most common key combination for switching between header and implementation files in xcode you can do that by swiping three fingers up or down.
Neato!!!
Get difference between two NSDate objects
Nov0
One of the most often asked questions is how to get difference between two NSDate objects. Since one of the most useful advices I’ve got while learning cocoa is using what’s there, I’d suggest all the folks look carefully at NSDate class reference documentation and see what it provides. Then just fireup the XCode and write this code into some method:
NSTimeInterval interval = [endDate timeIntervalSinceDate:startDate];
I presume you DO know how to get endDate and startDate object. Otherwise you shouldn’t be reading this. You’ll get the difference in seconds with fractions which is pure double. So you can do with it whatever you want. Feed it to some fancy number formatter, start countdown or what not. None of my business ,)
Oh, and btw, here’s a demo project for you to see this code in action: DateDifference XCode project.
How to listen to all possible notifications in 7 lines of code
Nov2
In the last post I mentioned about setting the background to your dragged image and sending the appropriate [private] notification so that Mac OS X would actually change it. At first it didn’t work so I thought that this notification is no longer valid (considering the fact that it’s private). So I’ve setup a little app for myself which listens to all possible notifications while run.
Main snippet that does all the job is put in 7 lines of code:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { NSDistributedNotificationCenter *dnc = [NSDistributedNotificationCenter defaultCenter]; [dnc addObserver:self selector:@selector(processNotification:) name:nil object:nil]; } - (void)processNotification:(id)notification { NSLog(@"Notification: %@", notification); }
So here’s another idea for another developer tool. Maybe there’s one that already exists, but it’d be really cool to have an app that registers all your your wanted notifications (either by name, app or any other parameter).
Quickly change desktop background
Nov2
Saturday morning. Can of RedBull. Cocoa. And me. Came up with a simple idea to develop an app for quickly changing desktop background. Just drag an image on an app window and you’re done!
Had to google around for some tips and tricks. First results disappointed me much since they referenced usage of Carbon and AppleEvents. Oh yeah, and they were dated back to 2004 or so. Then one post here had what I needed: a ChangeBackground and a [private] notification.
After couple of hours of trial and error I came up with this application that you can download and try out. I think I’m going to work on this app a bit more so it’d become more decent product.
It’s so rough that I can’t guarantee it will work on your Mac. But here’s the requirements so far:
- Snow Leopard
Download and [try to] enjoy. Needless to say – I accept any feedback.
UPDATE: Perspx found a bug which I successfully reproduced and fixed. You can download updated version here.
Centering NSWindow in Cocoa
Oct1
I was messing around with Cocoa. Building some dummy app to try out GData framework. I was creating preferences window and each time I ran the application – preferences window was showing somewhere not in the center of the screen. Yes, I know I can adjust the position via Size inspector for the window. Still, the adjustment area is so small I couldn’t adjust it correctly. And my OCD wanted pixel-perfect positioning. iGoogled and all I found was this NSWindow instance method:
[window center];
Note: it does not show your window on screen. This method only sets it’s frame to the center of the main (read – the one that has menu bar on top) screen.
Global hotkeys in Cocoa on Snow Leopard
Oct14
So I got this new MacBook Pro with Snow Leopard. One granny said that carbon won’t be supported on 64 bit platforms on Snow Leopard. So I was really interested how do I implement global hotkeys on 64 bit platform without using carbon.
NSEvent class addGlobalMonitorForEventsMatchingMask:handler: method provides this functionality. General declaration for this method looks like this:
+ (id)addGlobalMonitorForEventsMatchingMask:(NSEventMask)mask handler:(void (^)(NSEvent*))block
Since we’re monitoring the global event, block passed to method as event handler returns void (i.e. it can’t modify passed in event). But we can do anything we please inside the block. Most common usage pattern would be to activate an app and show it’s key window. It’s possible implement it in two ways: via window controller object or notifications.
Here how it’d look using window controller object (assuming MainWindowController is created before adding event monitor):
// AppDelegate.m - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { ... [NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask handler:^{ [NSApp activateIgnoringOtherApps:YES]; [mainWindowController showWindow:self]; }]; ... }
In example above – any key down while your app is inactive will activate your app and show window mainWindowController is responsible for.
The second one IMHO is cleaner and has wider application: using NSNotification. It requires code in application controller and application delegate. Both code pieces are independent.
// AppDelegate.m - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { [NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask handler:^{ ... int flags = [event modifierFlags]; int altDown = flags & NSOptionKeyMask; if (([event keyCode] == 7) && altDown) { [[NSNotificationCenter defaultCenter] postNotificationName:@"OpenMainWindow" object:nil]; }; ... }]; }; // AppController.m - (void)awakeFromNib { // Let's register for "OpenMainWindow" notification in AppController. NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(showMainWindow:) name:@"OpenMainWindow" object:nil]; } - (void)showMainWindow:(id)sender { // Open main window. Simple. [mainWindowController showWindow:sender]; }
UPDATE: as Antonio stated in the comments you need enable access for assistive devices via System Preferences app.
Reference: addGlobalMonitorForEventsMatchingMask:handler: @ Mac Dev Center