Monday, October 12, 2009

Book Review: Cocoa Design Patterns

cdp.png The Cocoa Design Patterns Book is one I've been anticipating for a while now and the first Cocoa book i've gotten in my hands that I've been really excited to read (i just finally got Bill Dudneys iPhone SDK book and Marcus Zarra's Core Data Book after I already started reading this.) Mac & iPhone Developers face a unique challenge when learning Cocoa in that you are learning 2 things at once, an Object Oriented Language (Objective-C) and the Cocoa Frameworks. As Aaron Hillegass has stated, you can easily learn Objective-C in a couple hours no problem. It's the Cocoa Frameworks that present a challenge to developing a good Mac or iPhone App and that is what this book explains. It takes you through lots of things I see people ask about on the mailing lists like why we use

MyObject *object = [[MyObject alloc] init];
instead of
MyObject *object = [MyObject new];
Overall it has 32 chapters and covers 28 Design Patterns used throughout Cocoa. I particularly liked their approach of going through a design pattern and stating the motivation behind using it, how it works and then also stating the consequences of using the design pattern mentioned and, finally they provide an overview of some areas of Cocoa in which the Design Pattern is used. It leaves you feeling like they really spent a lot of time trying to provide an objective overview of all the design patterns they cover. You might get the impression at first that this is a book for beginners, but then you'd be completely wrong. In fact I don't really felt at any time during reading this book that it was dumbed down for beginners or mentioned topics way to advanced for newcomers to Cocoa. It really felt like just about any Cocoa Developer (even veterans) could pick this up, understand it, and immediately begin using the content in their apps. I learned many things from this book, it filled in some small holes in my knowledge of why some parts of Cocoa operate the way they do. I think this book fills in a really important gap in that we've had intro books for learning Mac or iPhone Development, and we've had advanced books on Mac Development and now we are getting books on various areas of how Core Animation, Core Data, etc work, but we haven't really had anything that sat you down and explained all the various design patterns employed by Cocoa and the other Mac/iPhone frameworks, and how they work in such detail before now. Additionally it provides source code for each design pattern, to not only explain how it works, but takes you through an example of the design pattern in action. It covers a lot of things from MVC to Singletons to Categories, Notifications, Delegates, The Responder Chain, Invocations, etc. About the only thing this book doesn't cover is multithreaded design patterns in Cocoa (that could practically be a book just by itself), and even though it was published after Snow Leopard came out, it was written with Leopard in mind. Given all the other great material it covers I think it's a fair trade off. They even do a good job as well mentioning areas where using Garbage Collection changes something in your code. They briefly mention blocks once, but didn't really say anything more about it, I had wished they'd at least mention it's a feature coming to Snow Leopard. Given when they intended to publish this book I can't say though that I blame them for briefly mentioning as they did. About the only thing I wish this book had is a PDF version of this book so that I could have it on reference on my Mac and search through it at any time like I can with the Pragmatic Programmer Books. Update: people have pointed out they do have a PDF available on the InformIT website link in the comments. The Verdict To say I really liked this book would be a tremendous understatement. In conclusion I think just about every Cocoa Developer out there should get this book, Apple should practically be giving this away with Developer Memberships, it's that good. It doesn't matter if your using Cocoa for the Mac or iPhone, this book is something you should have, the material applies just as well to either area of development. Trust me, you'll be glad you got this book. It really gets you thinking about the design patterns you use in your own code, and how you could design your apps better. I know because it's already got me thinking more about the design patterns I use in my own projects.

Wednesday, September 30, 2009

New in Snow Leopard: New Mac OS X DTrace Providers

If you used Leopard and DTrace, then came to Snow Leopard there is a big treat for you (if you haven't used DTrace you can read my previous article Debugging Cocoa With DTrace Guide, go on read it and come back here... I'll wait), on Leopard on any given run I ran dtrace -l | wc -l I got about 23,000 probes on average. On Snow Leopard anytime I do the probe count I get about 66,000 (76,000 right before publishing with a lot of apps running) probes on average. So what's with the almost 3x increase in probes? Did Apple pull overtime and add a lot of DTrace probes to Mac OS X? Yes and no.

Yes in that now there are many more DTrace Mac OS X Specific Providers in Mac OS X 10.6 Snow Leopard than there were in 10.5 Leopard. Since there are many more providers they attach to each process that's applicable to them, and with all the processes running on your system you can see why your probe count has skyrocketed. It appears that Apple has made into providers what you previously had to get at by knowing the right methods to trace in the right libraries,etc, thus making tracing a particular aspect of an app or the whole OS easier.

Objective-C Runtime

//objc_runtime
24509 objc_runtime32972   libobjc.A.dylib          objc_exception_rethrow objc_exception_rethrow
24510 objc_runtime32972   libobjc.A.dylib          objc_exception_throw objc_exception_throw

Objective-C now has it's own provider for the (apparent) sole purpose of making Objective-C exceptions easy to catch. So you could run a script and catch all exception backtraces like so...

sh-3.2# dtrace -n 'objc_runtime$target:::objc_exception_throw { ustack(); }' -p 35467
dtrace: description 'objc_runtime$target:::objc_exception_throw ' matched 1 probe
CPU     ID                    FUNCTION:NAME
  1  90573 objc_exception_throw:objc_exception_throw
              libobjc.A.dylib`objc_exception_throw+0xb4
              CoreFoundation`+[NSException raise:format:arguments:]+0x67
              CoreFoundation`+[NSException raise:format:]+0x94
              Foundation`-[NSCFArray insertObject:atIndex:]+0x77
              CocoaPlugin`IBWrapIndex+0x3a5f
              CocoaPlugin`IBCounterpartTable+0xe3
              CocoaPlugin`IBCounterpartTable+0x130
              AppKit`-[NSToolbarView(_ItemDragAndDropSupport) dstDraggingDepositedAtPoint:draggingInfo:]+0x227
              AppKit`NSCoreDragReceiveProc+0x328
              HIServices`DoDropMessage+0x63
              HIServices`SendDropMessage+0x1f
              HIServices`DragInApplication+0x1c6
              HIServices`CoreDragStartDragging+0x27a
              AppKit`-[NSCoreDragManager _dragUntilMouseUp:accepted:]+0x2fb
              AppKit`-[NSCoreDragManager dragImage:fromWindow:at:offset:event:pasteboard:source:slideBack:]+0x63a
              AppKit`-[NSWindow(NSDrag) dragImage:at:offset:event:pasteboard:source:slideBack:]+0x92
              CocoaPlugin`IBCounterpartTable+0x6e06
              CocoaPlugin`IBCounterpartTable+0x4433
              InterfaceBuilderKit`-[IBEditorWindowController interceptEvent:]+0x5ca
              InterfaceBuilderKit`-[IBViewEditorWindowController interceptEvent:]+0xc2

 

1 90573 objc_exception_throw:objc_exception_throw libobjc.A.dylib`objc_exception_throw+0xb4 CoreFoundation`-[NSException raise]+0x9 AppKit`NSCoreDragReceiveProc+0x5fe HIServices`DoDropMessage+0x63 HIServices`SendDropMessage+0x1f HIServices`DragInApplication+0x1c6 HIServices`CoreDragStartDragging+0x27a AppKit`-[NSCoreDragManager _dragUntilMouseUp:accepted:]+0x2fb AppKit`-[NSCoreDragManager dragImage:fromWindow:at:offset:event:pasteboard:source:slideBack:]+0x63a AppKit`-[NSWindow(NSDrag) dragImage:at:offset:event:pasteboard:source:slideBack:]+0x92 CocoaPlugin`IBCounterpartTable+0x6e06 CocoaPlugin`IBCounterpartTable+0x4433 InterfaceBuilderKit`-[IBEditorWindowController interceptEvent:]+0x5ca InterfaceBuilderKit`-[IBViewEditorWindowController interceptEvent:]+0xc2 InterfaceBuilderKit`-[IBEditableWindow sendEvent:]+0x34 AppKit`-[NSApplication sendEvent:]+0x126d Interface Builder`0x1000038ad AppKit`-[NSApplication run]+0x1da AppKit`NSApplicationMain+0x16c Interface Builder`0x1000016a5

1 90573 objc_exception_throw:objc_exception_throw libobjc.A.dylib`objc_exception_throw+0xb4 CoreFoundation`-[NSException raise]+0x9 AppKit`-[NSCoreDragManager _dragUntilMouseUp:accepted:]+0x33e AppKit`-[NSCoreDragManager dragImage:fromWindow:at:offset:event:pasteboard:source:slideBack:]+0x63a AppKit`-[NSWindow(NSDrag) dragImage:at:offset:event:pasteboard:source:slideBack:]+0x92 CocoaPlugin`IBCounterpartTable+0x6e06 CocoaPlugin`IBCounterpartTable+0x4433 InterfaceBuilderKit`-[IBEditorWindowController interceptEvent:]+0x5ca InterfaceBuilderKit`-[IBViewEditorWindowController interceptEvent:]+0xc2 InterfaceBuilderKit`-[IBEditableWindow sendEvent:]+0x34 AppKit`-[NSApplication sendEvent:]+0x126d Interface Builder`0x1000038ad AppKit`-[NSApplication run]+0x1da AppKit`NSApplicationMain+0x16c Interface Builder`0x1000016a5 Interface Builder`0x100001634 Interface Builder`0x2

dtrace: pid 35467 has exited

This is a crash I got when adding a flexible space item to BWSelectableToolbar in Interface Builder.

 

OpenCL

//OpenCL Probes
21304 opencl_api32981            OpenCL                _CLQueueDeallocate commandqueuedeallocate
21305 opencl_api32981            OpenCL              _CLContextDeallocate contextdeallocate
21306 opencl_api32981            OpenCL                _CLEventDeallocate eventdeallocate
21307 opencl_api32981            OpenCL               _CLKernelDeallocate kerneldeallocate
21308 opencl_api32981            OpenCL                  _CLMemDeallocate memdeallocate
21309 opencl_api32981            OpenCL              _CLProgramDeallocate programdeallocate
21310 opencl_api32981            OpenCL                    clWaitForEvent waitforevent

Of course, OpenCL being a new technology in Snow Leopard has probes, all of the probes seen above appear to be for dealloc'ing items and 1 probe where OpenCL is waiting on events. I honestly have not gotten around to playing with OpenCL yet, but I expect to toy around with it and see what it's capable of sometime.

Cocoa Autorelease Provider

//Cocoa Autorelease Provider
22445 Cocoa_Autorelease32978    CoreFoundation    _CFAutoreleasePoolAddObject autorelease
22446 Cocoa_Autorelease32978    CoreFoundation    __NSAutoreleaseFreedObject error_freed_object
22447 Cocoa_Autorelease32978    CoreFoundation    __NSAutoreleaseNoPool error_no_pool
22448 Cocoa_Autorelease32978    CoreFoundation    _CFAutoreleasePoolPop pool_pop_end
22449 Cocoa_Autorelease32978    CoreFoundation    _CFAutoreleasePoolPop pool_pop_start
22450 Cocoa_Autorelease32978    CoreFoundation    _CFAutoreleasePoolPush pool_push

The Cocoa Autorelease provider is a great example of Apple adding a new provider that essentially makes it easier to grasp onto something that was already present in Mac OS X, but again you sort of had to know where to latch onto. It makes seeing the activity around Creating/Releasing NSAutoReleasePool objects and the objects you add to these pools easier. I picked on MarsEdit (which I am using to write this article) to see how this provider worked.

 

sh-3.2# dtrace -n 'Cocoa_Autorelease$target::: { ustack(); }' -p 38071
dtrace: description 'Cocoa_Autorelease$target::: ' matched 6 probes

 

0 30720 _CFAutoreleasePoolPush:pool_push CoreFoundation`_CFAutoreleasePoolPush+0xbe Foundation`-[NSAutoreleasePool init]+0x16 AppKit`-[NSApplication run]+0x2e7 AppKit`NSApplicationMain+0x23e MarsEdit`_start+0xd8 MarsEdit`start+0x29 MarsEdit`0x2

...

CPU ID FUNCTION:NAME 0 30715 _CFAutoreleasePoolAddObject:autorelease CoreFoundation`_CFAutoreleasePoolAddObject+0x185 CoreFoundation`-[NSObject(NSObject) autorelease]+0x1a AppKit`-[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]+0x16b AppKit`-[NSApplication run]+0x335 AppKit`NSApplicationMain+0x23e MarsEdit`_start+0xd8 MarsEdit`start+0x29 MarsEdit`0x2

..

0 30719 _CFAutoreleasePoolPop:pool_pop_start CoreFoundation`_CFAutoreleasePoolPop+0x93 Foundation`NSPopAutoreleasePool+0x189 Foundation`-[NSAutoreleasePool drain]+0x82 AppKit`-[NSApplication run]+0x3f5 AppKit`NSApplicationMain+0x23e MarsEdit`_start+0xd8 MarsEdit`start+0x29 MarsEdit`0x2

...

0 30718 _CFAutoreleasePoolPop:pool_pop_end CoreFoundation`_CFAutoreleasePoolPop+0x1d5 Foundation`NSPopAutoreleasePool+0x189 Foundation`-[NSAutoreleasePool drain]+0x82 AppKit`-[NSApplication run]+0x3f5 AppKit`NSApplicationMain+0x23e MarsEdit`_start+0xd8 MarsEdit`start+0x29 MarsEdit`0x2

 

I haven't yet seen the error_freed_object probe triggered, and I honestly don't know what would trigger it. All the documentation says is that the Cocoa Autorelease probes should be obvious where they are triggered and all of them except for the error_freed_object probe are obvious. I asked online what would trigger it and got back no responses. All I know is that the documentation should explain what this probe does better. I have had many hypothesizes about what could trigger it, but no amount of intentionally badly written code appears to trigger it. If you do find out what triggers it, please let me know.

Update: natevw seems to have solved it and now I know why it was never triggered

"__NSAutoreleaseFreedObject (error_freed_object) is similar to NSZombieEnabled. It tries to detect when an object that is already freed is being released by an autorelease pool. But unlinke NSZombie, it does not cause objects to hang around. So the memory could have been reused in the meantime.

 

Pre-10.6, you needed to set +[NSAutoreleasePool enableFreedObjectCheck:] to enable this. See NSDebug.h for more details and many other helpful goodies."

 

Garbage Collection

The garbage collection provider is technically nothing new, you could trace garbage collection before, but it's been made into it's own provider to make tracing garbage collection activities easier.

garbage_collection32978     libauto.dylib ... [Auto::ThreadLocalCollector::collect] collection_begin
garbage_collection32978     libauto.dylib ... [auto_collect_internal] collection_begin
garbage_collection32978     libauto.dylib ... [Auto::ThreadLocalCollector::process_local_garbage] collection_end
garbage_collection32978     libauto.dylib ... [auto_collect_internal] collection_end
garbage_collection32978     libauto.dylib ... [Auto::ThreadLocalCollector::collect] collection_phase_begin
garbage_collection32978     libauto.dylib ... [Auto::ThreadLocalCollector::scavenge_local] collection_phase_begin
garbage_collection32978     libauto.dylib ... [Auto::Zone::collect] collection_phase_begin
garbage_collection32978     libauto.dylib ... [auto_collect_internal] collection_phase_begin
garbage_collection32978     libauto.dylib ... [Auto::ThreadLocalCollector::collect] collection_phase_end
garbage_collection32978     libauto.dylib ... [Auto::ThreadLocalCollector::scavenge_local] collection_phase_end
garbage_collection32978     libauto.dylib ... [Auto::Zone::collect] collection_phase_end
garbage_collection32978     libauto.dylib ... [auto_collect_internal] collection_phase_end

QuickLookDaemon

If you care about QuickLook and how long it's spending on various tasks there are some new interesting probes. I've chopped the list down a bit for the sake of brevity here.

21402 QuickLookDaemon32981        quicklookd __-[QLDiskCacheQueryOperation main]_block_invoke_2 disk_cache_thumbnail_found
21403 QuickLookDaemon32981        quicklookd             _QLServerGetThumbnail dispatch_end
21404 QuickLookDaemon32981        quicklookd             _QLServerGetThumbnail dispatch_start
21405 QuickLookDaemon32981        quicklookd    -[_QLCacheThread serverIsIdle] idle_signal
21406 QuickLookDaemon32981        quicklookd -[QLMemoryCacheQueryOperation main] memory_cache_query_end
21407 QuickLookDaemon32981        quicklookd -[QLMemoryCacheQueryOperation main] memory_cache_query_start
21408 QuickLookDaemon32981        quicklookd -[QLMemoryCache addThumbnailData:] memory_cache_thumbnail_data_added
21409 QuickLookDaemon32981        quicklookd -[QLMemoryCacheQueryOperation main] memory_cache_thumbnail_found
21410 QuickLookDaemon32981        quicklookd __-[_QLServerThread serverWork]_block_invoke_4 saved_memory
21411 QuickLookDaemon32981        quicklookd -[_QLServerThread _dispatchThumbnailRequest:] thumbnail_generator_end
21412 QuickLookDaemon32981        quicklookd -[_QLServerThread _dispatchThumbnailRequest:] thumbnail_generator_start
21413 QuickLookDaemon32981        quicklookd                   -[QLManage run] waitfordtrace
21414 QuickLookDaemon32981        quicklookd -[_QLCacheThread serverIsWorking] work_signal

QLThumbnail

Along with the QuickLookDaemon there is a QLThumbnail provider...

29567 QLThumbnail32898         QuickLook                 QLThumbnailCancel cancel
29568 QLThumbnail32898         QuickLook                 QLThumbnailCreate create
29569 QLThumbnail32898         QuickLook            _QLThumbnailEndProcess end_generate
29570 QLThumbnail32898         QuickLook            _QLThumbnailCFFinalize finalized
29571 QLThumbnail32898         QuickLook _QLThumbnailSetThumbnailWithBitmapData generated
29572 QLThumbnail32898         QuickLook       _QLThumbnailRequestDispatch generated_but_empty
29573 QLThumbnail32898         QuickLook             _QLThumbnailSendQuery start_generate

Core Image

Core Image has been made into a provider for tracing kernel compiling, loading the kernels, tracing when contexts are created, etc.

26349 CoreImage32970        QuartzCore                 fe_kernel_compile coreImage_Kernel_Compile
26350 CoreImage32970        QuartzCore               fe_gl_load_programs coreImage_Kernel_ProgramLoad
26351 CoreImage32970        QuartzCore                 fe_context_cl_new coreImage_OpenCL_Context_Created
26352 CoreImage32970        QuartzCore                 fe_cl_load_kernel coreImage_OpenCL_Kernel_Loaded
26353 CoreImage32970        QuartzCore              fe_accel_read_bitmap coreImage_Readback_Image

JavaScript Core

Now you can easily see when JavaScript Core is doing it's garbage collection...

//JavaScriptCore
29562 JavaScriptCore32898    JavaScriptCore ... [JSC::Heap::collect] gc-begin
29563 JavaScriptCore32898    JavaScriptCore ... [JSC::Heap::collect] gc-end
29564 JavaScriptCore32898    JavaScriptCore ... [JSC::Heap::collect] gc-marked
29565 JavaScriptCore32898    JavaScriptCore ... [JSC::ProfileGenerator::didExecute] profile-did_execute
29566 JavaScriptCore32898    JavaScriptCore ... [JSC::ProfileGenerator::willExecute] profile-will_execute

Conclusion

There are many more new providers that I haven't even listed here, that will be interesting to various people, but I wanted to take you on a quick tour on what's new in Mac OS X from a DTrace perspective. If I can I will try and show some interesting things we can accomplish with these probes down the line. Overall I am glad Apple is really starting to put DTrace to good use from a native technology point of view, in that we no longer have to be just stuck looking through library calls and can now refer to a native Mac OS X provider that makes writing scripts and tracing our apps and the OS easier.

Monday, September 21, 2009

Xcode Shortcut Documents available under CC

Today I am releasing the original pages documents for the Xcode Shortcuts under the Creative Commons 3.0 Attribution License. Basically you can do with it, whatever you want as long as I am attributed as being the original author somewhere, and that's it. I've gotten many requests to alter the Xcode shortcuts to many desktop sizes and other various custom sizes and unfortunately I don't have the time available to alter it for all the requests I've gotten, so this (in addition to releasing it because I think it's just a good idea in general) I hope is a fair compromise that will allow you to edit it how you see fit. Once again the only thing I've done is remove the Xcode logo which you can easily paste back in there by opening the Xcode app package and in the Resources folder opening the appicon.icns file and then pasting the icon back in there. You can download the zip file containing the original Pages Documents here. You will need Pages '09 (part of iWork '09) in order to open the documents. Thanks for all your great feedback on the Xcode Shortcuts!

Thursday, September 17, 2009

Making NSOperation look like GCD

For my last article I posted, I realized that when coming up with code examples that I had been writing examples with NSOperation using it the same way I had been writing code with NSOperation before, namely creating a NSOperation object and adding it to the Queue. However, I overlooked that NSOperationQueue in 10.6 contains a -addOperationWithBlock: method. Using that you could indeed write code with NSOperationQueue that doesn't look too dissimilar from the GCD API like so

//GCD Recursive Decomposition
dispatch_queue_t queue = dispatch_queue_create("com.App.Task",NULL);
 
dispatch_async(queue,^{
	CGFloat num = [self doSomeMassiveComputation];
 
	dispatch_async(dispatch_get_main_queue(),^{
		[self updateUIWithNumber:num];
	});
});
 
//NSOperationQueue Recursive Decomposition
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue setName:@"com.App.Task"];
 
[queue addOperationWithBlock:^{
	CGFloat num = [self doSomeMassiveComputation];
 
	[[NSOperationQueue mainQueue] addOperationWithBlock:^{
		[self updateUIWithNumber:num];
	}];
}];
The only downside to this being that you can't get a reference to the newly created NSOperation object that it creates for you and change it before adding it to the queue, but this creates an Objective-C style way for accomplishing the same thing the GCD API does with only 1 extra line of code.

Wednesday, September 16, 2009

A Guide to Blocks & Grand Central Dispatch (and the Cocoa API's making use of them)

Intro As you may or may not know I recently did a talk at the Des Moines Cocoaheads in which I reviewed Blocks and Grand Central Dispatch. I have tried to capture the content of that talk and a lot more here in this article. The talk encompassed

  • Blocks
  • Grand Central Dispatch
  • GCD Design Patterns
  • Cocoa API's using GCD and Blocks

All of the content of this article applies only to Mac OS X 10.6 Snow Leopard as blocks support and Grand Central Dispatch are only available there. There are alternate methods to get blocks onto Mac OS X 10.5 and the iPhone OS via projects like Plausible Blocks which have blocks support, though do not have Grand Central Dispatch (libdispatch.)

Grand Central Dispatch is Open Source I should mention that Apple has in fact Open Sourced libdispatch (Grand Central Dispatch) on Mac OS Forge and the other components like Kernel Support for GCD (although if implemented on other OS's this is not necessary) and the blocks runtime support are all freely available and if you want you can even checkout the libdispatch repository using Git with the command git clone git://git.macosforge.org/libdispatch.git

Blocks

Blocks are part of a new C Language Extension, and are available in C, Objective-C, C++ and Objective-C++. Right off the bat, I should say that while we will use blocks with Grand Central Dispatch a lot later on, they are not required when using Grand Central Dispatch. Blocks are very useful onto themselves even if you never use them with anything else. However we gain a lot of benefit when we use blocks with Grand Central Dispatch, so pretty much all my examples here will use blocks.

What are blocks? Well let me show you a very basic example of one

^{ NSLog(@"Inside a block"); }

This is a very basic example of a block, but it is basically a block that accepts no arguments and contains a NSLog() statement. Think of blocks as either a method or snippet of code that accepts arguments and captures lexical scope. Other languages have already had something like this concept implemented for a while (since the 70's at least if I remember correctly.) Here's a couple examples of this concept in one of my favorite languages Python

>>>f = lambda x,y,z: x + y + z
...
>>> f(2,3,4)
9

Here we are defining a lambda in Python which is basically a function that we can execute later on. In Python after the lambda keyword you define the arguments that you are passing in to the left of the colon and the right is the actual expression that will get executed. So in the first line of code we've defined a lambda that accepts 3 arguments and when it's invoked all it will do is accept the arguments and add them together, hence when we invoke f like f(2,3,4) we get 9 back. We can do more with Python lambda's. Python has functions that actually do more with lambdas like in this example...

>>>reduce((lambda x,y: x+y),[1,2,3,4])
10
>>>reduce((lambda x,y: x*y),[1,2,3,4])
24

This reduce function uses a lambda that accepts 2 arguments to iterate over an array. The lambda in this case accepts 2 arguments (as the reduce function requires) and in the first example just iterates over the array with it. Python begins by calling the lambda using the first 2 elements of the array then gets a resulting value and again calls the lambda with that resulting value and the next element in the array and keeps on calling the lambda until it has fully iterated over the data set. So in other words the function is executed like so (((1 + 2) + 3) + 4)

Blocks bring this concept to C and do a lot more. You might ask yourself "But haven't we already had this in C? I mean there are C Function Pointers." Well yeah, but while blocks are similar in concept, they do a lot more than C Function Pointers, and even better if you already know how to use C function pointers, Blocks should be fairly easy to pick up.

Here is a C Function Pointer Declaration...

 void (*func)(void); 

...and here is a Block Declaration...

 void (^block)(void); 

Both define a function that returns nothing (void) and takes no arguments. The only difference is that we've changed the name and swapped out a "*" for a "^". So lets create a basic block

 int (^MyBlock)(int) = ^(int num) { return num * 3; }; 

The block is laid out like so. The first part signifies that it's a block returning an int. The (^MyBlock)(int) is defining a block of the MyBlock type that accepts an int as an argument. Then the ^(int num) to the right of the assignment operator is the beginning of the block, it means this is a block that accepts an int as an argument (matching the declaration earlier.) Then the { return num * 3; }; is the actual body of the block that will be executed.

When we've defined the block as shown earlier we can then assign it to variables and pass it in as arguments like so...

int aNum = MyBlock(3);

printf(“Num %i”,aNum); //9 

Blocks Capturing Scope: When I said earlier that blocks capture lexical scope this is what I mean, blocks are not only useful to use as a replacement for c function pointers, but they also capture the state of any references you use within the block itself. Let me show you...

int spec = 4;
 
int (^MyBlock)(int) = ^(int aNum){
 return aNum * spec;
};

spec = 0;
printf("Block value is %d",MyBlock(4));

Here we've done a few things. First I declared an integer and assigned it a value of 4. Then we created the block and assigned it to an actual block implementation and finally called the block in a printf statement. And finally it prints out "Block value is 16"? Wait we changed the spec number to 0 just before we called it didn't we? Well yes actually we did. But what blocks do actually is create a const copy of anything you reference in the block itself that is not passed in as an argument. So in other words we can change the variable spec to anything we want after assigning the block, but unless we are passing in the variable as an argument the block will always return 16 assuming we are calling it as MyBlock(4). I should also note that we can also use C's typedef utility to make referencing this type of block easier. So in other words...

int spec = 4;
 
typedef int (^MyBlock)(int);
 
MyBlock InBlock = ^(int aNum){
 return aNum * spec;
};

spec = 0;
printf("InBlock value is %d",InBlock(4));

is exactly equivalent to the previous code example. The difference being is that the latter is more readable.

__block Blocks do have a new storage attribute that you can affix onto variables. Lets say that in the previous example we want the block to read in our spec variable by reference so that when we do change the variable spec that our call to InBlock(4) actually returns what we expect it to return which is 0. To do so all we need to change is adding __block to spec like so...

__block int spec = 4;
 
typedef int (^MyBlock)(int);
 
MyBlock InBlock = ^(int aNum){
 return aNum * spec;
};

spec = 0;
printf("InBlock value is %d",InBlock(4));

and now the printf statement finally spits out "InBlock value is 0", because now it's reading in the variable spec by reference instead of using the const copy it would otherwise use.

Blocks as Objective-C objects and more! Naturally going through this you'd almost be thinking right now that blocks are great, but they could potentially have some problems with Objective-C, not so Blocks are Objective-C objects! They do have a isa pointer and do respond to basic commands like -copy and -release which means we can use them in Objective-C dot syntax like so...

@property(copy) void(^myCallback)(id obj);
@property(readwrite,copy) MyBlock inBlock;

and in your Objective-C code you can call your blocks just like so self.inBlock();.

Finally I should note that while debugging your code there is a new GDB command specifically for calling blocks like so

$gdb invoke-block MyBlock 12 //like MyBlock(12)
$gdb invoke-block StringBlock “\” String \”” 

These give you the ability to call your blocks and pass in arguments to them during your debug sessions.

Grand Central Dispatch

Now onto Grand Central Dispatch (which I may just reference as GCD from here on out.) Unlike past additions to Mac OS X like say NSOperation/NSThread Subclasses, Grand Central Dispatch is not just a new abstraction around what we've already been using, it's an entire new underlying mechanism that makes multithreading easier and makes it easy to be as concurrent as your code can be without worrying about the variables like how much work your CPU cores are doing, how many CPU cores you have and how much threads you should spawn in response. You just use the Grand Central Dispatch API's and it handles the work of doing the appropriate amount of work. This is also not just in Cocoa, anything running on Mac OS X 10.6 Snow Leopard can take advantage of Grand Central Dispatch ( libdispatch ) because it's included in libSystem.dylib and all you need to do is include #import <dispatch/dispatch.h> in your app and you'll be able to take advantage of Grand Central Dispatch.

Grand Central Dispatch also has some other nice benefits. I've mentioned this before in other talks, but in OS design there are 2 main memory spaces (kernel space and user land.) When code you call executes a syscall and digs down into the kernel you pay a time penalty for doing so. Grand Central Dispatch will try and do it's best with some of it's API's and by pass the kernel to return to your application without digging into the kernel which means this is very fast. However if GCD needs to it can go down into the kernel and execute the equivalent system call and return back to your application.

Lastly GCD does some things that threading solutions in Leopard and earlier did not do. For example NSOperationQueue in Leopard took in NSOperation objects and created a thread, ran the NSOperation -(void)main on the thread and then killed the thread and repeated the process for each NSOperation object it ran, pretty much all we did on Leopard and earlier was creating threads, running them and then killing the threads. Grand Central Dispatch however has a pool of threads. When you call into GCD it will give you a thread that you run your code on and then when it's done it will give the thread back to GCD. Additionally queues in GCD will (when they have multiple blocks to run) just keep the same thread(s) running and run multiple blocks on the thread, which gives you a nice speed boost, and only then when it has no more work to do hand the thread back to GCD. So with GCD on Snow Leopard we are getting a nice speed boost just by using it because we are reusing resources over and over again and then we we aren't using them we just give them back to the system.

This makes GCD very nice to work with, it's very fast, efficient and light on your system. Even though GCD is fast and light however you should make sure that when you give blocks to GCD that there is enough work to do such that it's worth it to use a thread and concurrency. You can also create as many queues as you want to match however many tasks you are doing, the only constraint is the memory available on the users system.

GCD API So if we have a basic block again like this

^{ NSLog(@"Doing something"); }

then to get this running on another thread all we need to do is use dispatch_async() like so...

dispatch_async(queue,^{
 NSLog(@"Doing something");
});

so where did that queue reference come from? Well we just need to create or get a reference to a Grand Central Dispatch Queue ( dispatch_queue_t ) like this

dispatch_queue_t queue = dispatch_get_global_queue(0,0);

which just in case you've seen this code is equivalent to

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

In Grand Central dispatch the two most basic things you'll deal with are queues (dispatch_queue_t) and the API's to submit blocks to a queue such as dispatch_async() or dispatch_sync() and I'll explain the difference between the two later on. For now let's look at the GCD Queues.

The Main Queue The Main Queue in GCD is analogous to the main app thread (aka the AppKit thread.) The Main Queue cooperates with NSApplicationMain() to schedule blocks you submit to it to run on the main thread. This will be very handy to use later on, for now this is how you get a handle to the main queue

dispatch_queue_t main = dispatch_get_main_queue();

or you could just call get main queue inside of a dispatch call like so

dispatch_async(dispatch_get_main_queue(),^ {....

The Global Queues The next type of queue in GCD are the global queues. You have 3 of them of which you can submit blocks to. The only difference to them are the priority in which blocks are dequeued. GCD defines the following priorities which help you get a reference to each of the queues...

enum {
 DISPATCH_QUEUE_PRIORITY_HIGH = 2,
 DISPATCH_QUEUE_PRIORITY_DEFAULT = 0,
 DISPATCH_QUEUE_PRIORITY_LOW = -2,
};

When you call dispatch_get_global_queue() with DISPATCH_QUEUE_PRIORITY_HIGH as the first argument you've got a reference to the high global queue and so on for the default and low. As I said earlier the only difference is the order in which GCD will empty the queues. By default it will go and dequeue the high priority queue's blocks, then dequeue the default queues blocks and then the low. This priority doesn't really have anything to do with CPU time.

Private Queues Finally there are the private queues, these are your own queues that dequeue blocks serially. You can create them like so

dispatch_queue_t queue = dispatch_queue_create("com.MyApp.AppTask",NULL);

The first argument to dispatch_queue_create() is essentially a C string which represents the label for the queue. This label is important for several reasons

  • You can see it when running Debug tools on your app such as Instruments
  • If your app crashes in a private queue the label will show up on the crash report
  • As there are going to be lots of queues on 10.6 it's a good idea to differentiate them

By default when you create your private queues they actually all point to the default global queue. Yes you can point these queues to other queues to make a queue hierarchy using dispatch_set_target_queue(). The only thing Apple discourages is making an loop graph where you make a queue that points to another and another eventually winding back to pointing at the first one because that behavior is undefined. So you can create a queue and set it to the high priority queue or even any other queue like so

dispatch_queue_t queue = dispatch_queue_create("com.App.AppTask,0);
dispatch_queue_t high = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,NULL);

dispatch_set_target_queue(queue,high);

If you wanted to you could do the exact same with your own queues to create the queue hierarchies that I described earlier on.

Suspending Queues Additionally you may need to suspend queue's which you can do with dispatch_suspend(queue). This runs exactly like NSOperationQueue in that it won't suspend execution of the current block, but it will stop the queue dequeueing any more blocks. You should be aware of how you do this though, for example in the next example it's not clear at all what's actually run

dispatch_async(queue,^{ NSLog(@"First Block"); });
dispatch_async(queue,^{ NSLog(@"Second Block"); });
dispatch_async(queue,^{ NSLog(@"Third Block"); });

dispatch_suspend(queue);

In the above example it's not clear at all what has run, because it's entirely possible that any combination of blocks may have run.

Memory Management It may seem a bit odd, but even in fully Garbage Collected code you still have to call dispatch_retain() and dispatch_release() on your grand central dispatch objects, because as of right now they don't participate in garbage collection.

Recursive Decomposition Now calling dispatch_async() is okay to run code in a background thread, but we need to update that work back in the main thread, how how would one go about this? Well we can use that main queue and just dispatch_async() back to the main thread from within the first dispatch_async() call and update the UI there. Apple has referred to this as recursive decomposition, and it works like this

dispatch_queue_t queue = dispatch_queue_create(“com.app.task”,NULL)
dispatch_queue_t main = dispatch_get_main_queue();

dispatch_async(queue,^{
 CGFLoat num = [self doSomeMassiveComputation];

 dispatch_async(main,^{
  [self updateUIWithNumber:num];
 });
});

In this bit of code the computation is offloaded onto a background thread with dispatch_async() and then all we need to do is dispatch_async() back into the main queue which will schedule our block to run with the updated data that we computed in the background thread. This is generally the most preferable approach to using grand central dispatch is that it works best with this asynchronous design pattern. If you really need to use dispatch_sync() and absolutely make sure a block has run before going on for some reason, you could accomplish the same thing with this bit of code

dispatch_queue_t queue = dispatch_queue_create(“com.app.task”,NULL);

__block CGFloat num = 0;

dispatch_sync(queue,^{
 num = [self doSomeMassiveComputation];
});

[self updateUIWithNumber:num];

dispatch_sync() works just like dispatch_async() in that it takes a queue as an argument and a block to submit to the queue, but dispatch_sync() does not return until the block you've submitted to the queue has finished executing. So in other words the [self updateUIWithNumber:num]; code is guaranteed to not execute before the code in the block has finished running on another thread. dispatch_sync() will work just fine, but remember that Grand Central Dispatch works best with asynchronous design patterns like the first bit of code where we simply dispatch_async() back to the main queue to update the user interface as appropriate.

dispatch_apply() dispatch_async() and dispatch_sync() are all okay for dispatching bits of code one at a time, but if you need to dispatch many blocks at once this is inefficient. You could use a for loop to dispatch many blocks, but luckly GCD has a built in function for doing this and automatically waiting till the blocks all have executed. dispatch_apply() is really aimed at going through an array of items and then continuing execution of code after all the blocks have executed, like so

dispatch_queue_t queue = dispatch_get_global_queue(0,0);

dispatch_apply(queue, count, ^(size_t idx){
 do_something_with_data(data,idx);
});

//do something with data 

This is GCD's way of going through arrays, you'll see later on that Apple has added Cocoa API's for accomplishing this with NSArrays's, NSSets,etc. dispatch_apply() will take your block and iterate over the array as concurrently as it can. I've run it sometimes where it takes the indexes 0,2,4,6,8 on Core 1 and 1,3,5,7,9 on Core 2 and sometimes it's done odd patterns where it does most of the items on 1 and some on core 2, the point being that you don't know how concurrent it will be, but you do know GCD will iterate over your array or dispatch all the blocks within the max count you give it as concurrently as it can and then once it's done you just go on and work with your updated data.

Dispatch Groups Dispatch Groups were created to group several blocks together and then dispatch another block upon all the blocks in the group completing their execution. Groups are setup very easily and the syntax isn't very dissimilar from dispatch_async(). The API dispatch_group_notify() is what sets the final block to be executed upon all the other blocks finishing their execution.

dispatch_queue_t queue = dispatch_get_global_queue(0,0);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group,queue,^{
 NSLog(@"Block 1");
});

dispatch_group_async(group,queue,^{
 NSLog(@"Block 2");
});

dispatch_group_notify(group,queue,^{
 NSLog(@"Final block is executed last after 1 and 2");
});

Other GCD API you may be Interested in

//Make sure GCD Dispatches a block only 1 time
dispatch_once()

//Dispatch a Block after a period of time
dispatch_after()

//Print Debugging Information
dispatch_debug()

//Create a new dispatch source to monitor low-level System objects
//and automatically submit a handler block to a dispatch queue in response to events.
dispatch_source_create() 

Cocoa & Grand Central Dispatch/Blocks

The GCD API's for being low level API's are very easy to write and quite frankly I love them and have no problem using them, but they are not appropriate for all situations. Apple has implemented many new API's in Mac OS X 10.6 Snow Leopard that take advantage of Blocks and Grand Central Dispatch such that you can work with existing classes easier & faster and when possible concurrently.

NSOperation and NSBlockOperation NSOperation has been entirely rewritten on top of GCD to take advantage of it and provide some new functionality. In Leopard when you used NSOperation(Queue) it created and killed a thread for every NSOperation object, in Mac OS X 10.6 now it uses GCD and will reuse threads to give you a nice performance boost. Additionally Apple has added a new NSOperation subclass called NSBlockOperation to which you can add a block and add multiple blocks. Apple has additionally added a completion block method to NSOperation where you can specify a block to be executed upon a NSOperation object completing (goodbye KVO for many NSOperation Objects.)

NSBlockOperation can be a nice easy way to use everything that NSOperation offers and still use blocks with NSOperation.

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
 NSLog(@"Doing something...");
}];

//you can add more blocks
[operation addExecutionBlock:^{
 NSLog(@"Another block");
}];

[operation setCompletionBlock:^{
 NSLog(@"Doing something once the operation has finished...");
}];

[queue addOperation:operation];

in this way it starts to make the NSBlockOperation look exactly like high level dispatch groups in that you can add multiple blocks and set a completion block to be executed.

Concurrent Enumeration Methods

One of the biggest implications of Blocks and Grand Central Dispatch is adding support for them throughout the Cocoa API's to make working with Cocoa/Objective-C easier and faster. Here are a couple of examples of enumerating over a NSDictionary using just a block and enumerating over a block concurrently.

//non concurrent dictionary enumeration with a block
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  NSLog(@"Enumerating Key %@ and Value %@",key,obj);
 }];

//concurrent dictionary enumeration with a block
[dict enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent
    usingBlock:^(id key, id obj, BOOL *stop) {
     NSLog(@"Enumerating Key %@ and Value %@",key,obj);
    }];

The Documentation is a little dry on what happens here saying just "Applies a given block object to the entries of the receiver." What it doesn't make mention of is that because it has a block reference it can do this concurrently and GCD will take care of all the details of how it accomplishes this concurrency for you. You could also use the BOOL *stop pointer and search for objects inside NSDictionary and just set *stop = YES; to stop any further enumeration inside the block once you've found the key you are looking for.

High Level Cocoa API's vs Low Level GCD API's

Chris Hanson earlier wrote about why you should use NSOperation vs GCD API's. He does make some good points, however I will say that I haven't actually used NSOperation yet on Mac OS X 10.6 (although I definitely will be using it later on in the development of my app) because the Grand Central Dispatch API's are very easy to use and read and I really enjoy using them. Although he wants you to use NSOperation, I would say use what you like and is appropriate to the situation. I would say one reason I really haven't used NSOperation is because when GCD was introduced at WWDC, I heard over and over about the GCD API, and I saw how great it was and I can't really remember NSOperation or NSBlockOperation being talked about much.

To Chris's credit he does make good points about NSOperation handling dependencies better and you can use KVO if you need to use it with NSOperation Objects. Just about all the things you can do with the basic GCD API's you can accomplish with NSOperation(Queue) with the same or a minimal couple lines of more code to get the same effect. There are also several Cocoa API that are specifically meant to be used with NSOperationQueue's, so in those cases you really have no choice but to use NSOperationQueue anyway.

Overall I'd say think what you'll need to do and why you would need GCD or NSOperation(Queue) and pick appropriately. If you need to you can always write NSBlockOperation objects and then at some point later on convert those blocks to using the GCD API with a minimal amount of effort.

Further Reading on Grand Central Dispatch/Blocks

Because I only have so much time to write here, and have to split my time between work and multiple projects, I am linking to people I like who have written some great information about Grand Central Dispatch and/or Blocks. Although this article will most definitely not be my last on Grand Central Dispatch and/or Blocks.

http://www.friday.com/bbum/2009/08/29/basic-blocks/ http://www.friday.com/bbum/2009/08/29/blocks-tips-tricks/ http://www.mikeash.com/?page=pyblog/friday-qa-2009-08-28-intro-to-grand-central-dispatch-part-i-basics-and-dispatch-queues.html http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html

A couple projects making nice use of Blocks

http://github.com/amazingsyco/sscore Andy Matauschak's KVO with Blocks http://gist.github.com/153676

Interesting Cocoa API's Making Use of Blocks

A list of some of the Cocoa API's that make use of blocks (thanks to a certain someone for doing this, really appreciate it.) I should note that Apple has tried not to use the word block everywhere in it's API for a very good reason. When you come to a new API and you saw something like -[NSArray block] you would probably think it had something to do with blocking using the NSArray or something where you are blocking execution. Although many API do have block in their name, it is by no means the only keyword you should use when looking for API's dealing with blocks, for these links to work you must have the Documentation installed on your HD.

NSEvent

addGlobalMonitorForEventsMatchingMask:handler:

addLocalMonitorForEventsMatchingMask:handler:

NSSavePanel

beginSheetModalForWindow:completionHandler:

beginWithCompletionHandler:

NSWorkspace

duplicateURLs:completionHandler:

recycleURLs:completionHandler:

NSUserInterfaceItemSearching Protocol

searchForItemsWithSearchString:resultLimit: matchedItemHandler:

NSArray

enumerateObjectsAtIndexes:options:usingBlock:

enumerateObjectsUsingBlock:

enumerateObjectsWithOptions:usingBlock:

indexesOfObjectsAtIndexes:options:passingTest:

indexesOfObjectsPassingTest:

indexesOfObjectsWithOptions:passingTest:

indexOfObjectAtIndexes:options:passingTest:

indexOfObjectAtIndexes:options:passingTest:

indexOfObjectPassingTest:

indexOfObjectWithOptions:passingTest:

indexOfObjectWithOptions:passingTest:

NSAttributedString

enumerateAttribute:inRange:options:usingBlock:

enumerateAttributesInRange:options:usingBlock:

NSBlockOperation

blockOperationWithBlock:

addExecutionBlock:

executionBlocks

NSDictionary

enumerateKeysAndObjectsUsingBlock:

enumerateKeysAndObjectsWithOptions:usingBlock:

keysOfEntriesPassingTest:

keysOfEntriesWithOptions:passingTest:

NSExpression

expressionForBlock:arguments:

expressionBlock

NSFileManager

enumeratorAtURL:includingPropertiesForKeys: options:errorHandler:

NSIndexSet

enumerateIndexesInRange:options:usingBlock:

enumerateIndexesUsingBlock:

enumerateIndexesWithOptions:usingBlock:

indexesInRange:options:passingTest:

indexesPassingTest:

indexesWithOptions:passingTest:

indexInRange:options:passingTest:

indexPassingTest:

indexWithOptions:passingTest:

NSNotificationCenter

addObserverForName:object:queue:usingBlock:

NSOperation

completionBlock

setCompletionBlock:

NSOperationQueue

addOperationWithBlock:

NSPredicate

predicateWithBlock:

NSSet

enumerateObjectsUsingBlock:

enumerateObjectsWithOptions:usingBlock:

objectsPassingTest:

objectsWithOptions:passingTest:

NSString

enumerateLinesUsingBlock:

enumerateSubstringsInRange:options:usingBlock:

CATransaction

completionBlock

Monday, September 07, 2009

Des Moines CocoaHeads: Blocks & Grand Central Dispatch (Updated with Room#)

This Thursday I will be doing a presentation at the Des Moines Cocoaheads (at Iowa State University Campus Howe Hall Room 20. It's on the lower level of Howe, just go down the main stairs by the front door and you'll see room 20 straight ahead.) on Blocks & Grand Central Dispatch and how you can use them with Cocoa, if your in or near central Iowa come by and say hello to the other Iowa Cocoaheads. I intend to do a general overview of

  • Blocks Syntax & Usage
  • Grand Central Dispatch: How it works, the API's and design patterns
  • Cocoa API's using Blocks & GCD
Sometime afterwards I will post either a article/and or video covering the content in this presentation, plus a lot more comprehensive material that I will not be able to fit into the talk.
NSCoder Night
Also if your around Central Iowa there is NSCoder Night every week on Tuesday at about 7pm alternating between Panera Bread in Ames & Ankeny. See the Google Calendar to see where NSCoder Night is for the current week. Tomorrow Sept 8 we will be at Panera Bread in Ankeny at ~7pm. See you there!

Friday, August 28, 2009

Xcode Shortcuts Updated for Xcode 3.2 on Mac OS X 10.6 Snow Leopard

Xcode Shortcuts (PDF) Xcode Shortcuts (Black & White) (PDF)

Update The original Pages Documents used to make this are now freely available under the Creative Commons License, see more info here

I've gone ahead and updated the Xcode Shortcuts list for Xcode 3.2 on Mac OS X 10.6 Snow Leopard. Although I go to great lengths to ensure accuracy and correctness it could have the rare error. If you spot an error feel free to email me and let me know and I will try and put out an update as soon as I can. Overall some very nice new keyboard shortcuts, and some terminology has changed, but most of your common operations shortcuts should remain the same. As always feel free to share this, I highly encourage it. I will again put out the Original Pages documents under the Creative Commons License, but for now I am just putting out PDF's. Thanks!

Saturday, June 06, 2009

See you at WWDC!

wwdc_intro.png
I am taking just a few minutes to write this in the middle of packing my things for WWDC. This will be my 3rd time going to WWDC and my last time officially as a student.
packing.png
Already I have learned a great deal of things from the previous times i've gone. I've made an effort to get up earlier to get used to what will be a normal time to get up in a different time zone. Also I know Kevin Hoctor has said this several times and now I totally agree with him after trying 2x in a row... don't go to all the sessions. This event is a social event as much as a learning event, in the past I literally went to mostly sessions and didn't really leave any session and boy did I pay the price for it mentally and physically. It's very tempting to try and go to all the sessions and try to leech off every little bit of information you can from the Apple presenters, trust me you'd do good to take a break and besides you'll learn more from reviewing the videos after the conference. One of my goals is this year is to try and network more, I have business cards now and I plan to try and take breaks from sessions. If you see me, feel free to say hi!
me.png
This year there are a bunch of people from Twitter that I really want to meet. I plan to attend the SFMacIndie party on Sunday night, but beyond that I don't have a whole lot set in stone right now. Overall I am really excited this year and can't wait to arrive in San Francisco tomorrow! I'll see you there! top photo from http://www.flickr.com/photos/hexholden/2564484035/

Saturday, April 18, 2009

Distributed Version Control & Git [Part 2]

dvcs.png
In Part I of Distributed Version Control & Git, I showed you why you should switch to Distributed Version Control and explained part of what makes Git a compelling Distributed Version Control System. In Part 2 and the final part of this miniseries, I show you an overview of git and the basics and guide you through how you setup a git repository, doing commits, branches, merging, resolving merge conflicts with filemerge and show you the apps that come with git and GitX. I also want to draw your attention to the fact that there are some excellent & much more detailed git tutorial videos that go into much more detail at GitCasts Here are some more interesting resources GitX GitCast Videos Setup Initialization & Cloning Normal Workflow Interactive Adding Git Log Browsing Git Objects Branching & Merging Rebasing Distributed Workflow Empty Branches RailsConf Git Talk Git Submodules Git Diff

Monday, April 13, 2009

Distributed Version Control & Git [Part 1]

dvcs.png
This is a video based off a talk I gave on Distributed Version Control for the Des Moines Cocoaheads and gave an example of how to use it in the context of git. The premise of my talk was showing why you should switch to distributed version control and showing off some cool things it can do. Today I seriously believe that with few rare exceptions do we really need centralized version control, in addition Subversions merging is broken and these distributed systems tend to do branching & merging in a much more pleasant manner that actually makes things enjoyable. Literally when you start using Distributed Version Control you tend to start making a lot of branches and do many more merges, it becomes you do commits and merges when you want to vs doing them in some regularity because you fear your version control system might make things harder if you don't commit or merge now. Check in later for Part 2 where I demonstrate some features in git in another screencast... for now here are some things to get you started Git Homepage The way I'd recommend people install Git Git OS X Installer (Google Code Project) Git Cheat Sheet Gitx App Pragmatic Programmers: Pragmatic Version Control Using Git [Book] Linus Torvalds Google Tech Talk on Git Randal Scwartz Google Tech Talk on Git

Thursday, March 26, 2009

Global Keyboard Shortcuts with Carbon Events

If your new to Cocoa you've probably not heard of Carbon, on the other hand if you've been developing for the Mac for a while now you've probably at least heard of Carbon and if you're really experienced you've probably used carbon. If you've used carbon at all this article really isn't for you. What I want to do is gently introduce you to carbon events, the 1 scenario where we'd use it for in terms of cocoa apps, why Cocoa Events can't handle this one scenario and why Carbon Events can, and how to implement it in a Cocoa Application. Why Carbon Events There is a specific scenario I had in mind as to why you would use Carbon Events ( actually if you have a Cocoa app it's a you have to use Carbon Events), the scenario is this: you have a Cocoa application and you know your customers will be running it but it will not be the active application running in the foreground, your customers may be looking at Mail, NetNewsWire, Xcode, etc basically some other application than yours and yet you still want to receive a keyboard shortcut key pressed event. How do you do this? Not with Cocoa, in its current form it's literally impossible. Here's why Cocoa Events works as such, according to the Cocoa Event Handling Guide it says "In the main event loop, the application object (NSApp) continuously gets the next (topmost) event in the event queue, converts it to an NSEvent object, and dispatches it toward its final destination. It performs this fetching of events by invoking the nextEventMatchingMask:untilDate:inMode:dequeue: method in a closed loop. When there are no events in the event queue, this method blocks, resuming only when there are more events to process." It then goes on "After fetching and converting an event, NSApp performs the first stage of event dispatching in the sendEvent: method. In most cases NSApp merely forwards the event to the window in which the user action occurred by invoking the sendEvent: method of that NSWindow object. The window object then dispatches most events to the NSView object associated with the user action in an NSResponder message such as mouseDown: or keyDown:. An event message includes as its sole argument an NSEvent object describing the event."

cocoasamurai_nsevent_window_button.png
So in other words the NSApplication has an event queue and receives an event (1) converts it into NSEvent objects (2) which it then forwards to a Window (3) which then dispatches the event to the view associated with the user action calling on it -mouseDown:(NSEvent *)event, -keyDown:(NSEvent *)event, etc (4). This is great, but if our application is running in the background there is no way our Window will receive events. Cocoa Events simply does not allow for a regular cocoa application to be in the background and receive keyboard events. Now I could go on to further explain NSResponder and how it events could then go onto the menu's after exhausting all possible views in a window that could respond to an event, but that's another article onto itself. The point is our app is a regular cocoa app and it has a window and menu's, but we know our application is not going to have focus and thus won't have a window that can forward events or even application menu's to receive events, but we still want to receive an event and invoke some sort of functionality. There are plenty of examples of this: OmniFocus has a quick entry window which you can invoke from anywhere, applications like Quicksilver use Carbon Events so you can invoke them anywhere from in Mac OS X. These are both Cocoa applications, but they depend on Carbon Events to give them notifications of global keyboard shortcut events. Conceptually Carbon events is vastly different from Cocoa Events. When I first finally got a Carbon Events example working it seemed very strange compared to Cocoa Events, it was more like there is a stream of events going by in the system and you install something to indicate a interest in a particular kind of event. If that event matches the specific event you are looking for then your code is called and you have a global keyboard shortcut. So how do we do this? Setting up a project In Xcode, go ahead and create a new Cocoa application. At this point if you build in go all you will have is a small window and an application that does nothing. Now go to File->New File and create a plain Cocoa class and call it AppController. Then click on the disclosure triangle by the Frameworks folder and then right-click on Linked Frameworks and go to Add -> Existing Frameworks and in your SDK add "Carbon.Framework." At this point this should be all you have for AppController.h
#import <Cocoa/Cocoa.h> @interface AppController : NSObject { } @end
Now in AppController.m add #import <Carbon/Carbon.h> and implement -(void)awakeFromNib and you should have
#import "AppController.h" #import <Carbon/Carbon.h> @implementation AppController -(void)awakeFromNib { } @end
Now the next thing we need to do is add the declaration for our method which will handle the global keyboard shortcut. Above the "@implementation AppController" add the following line
OSStatus myHotKeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData);
this method will be the rough equivalent of implementing say -(void)mouseDown:(NSEvent *)event in a cocoa class. The Carbon Event handler will pass the EventHandlerCallRef (next event handler reference), EventRef (roughly equivalent to NSEvent) arguments to us. If we were doing really deep Carbon Events work then we might also be interested in all the arguments, but for this simplistic task all we need is the EventRef reference. Into the guts of Carbon Events Now we've set the foundation so now lets go to work in the awake from Nib method. Add the following code to the top of the awakeFromNib Method
    EventHotKeyRef myHotKeyRef;     EventHotKeyID myHotKeyID;     EventTypeSpec eventType;
Now lets understand these new variables. EventHotKeyRef : The documentation is pretty descriptive about this "Represents a registered global hot key." In essence we have this reference so we can unregister it later if we want to. EventHotKeyID : Again "Represents the ID of a global hot key." This is where you'll set some things to uniquely identify your global keyboard shortcut. EventTypeSpec : "Describes the class and kind of an event." Passing in this reference after setting the class and kind of event tells the event handler what type of event this is. So lets set the EventTypeSpec reference
    eventType.eventClass=kEventClassKeyboard;     eventType.eventKind=kEventHotKeyPressed;
This will tell the event handler we are looking for a keyboard event and that a hot key was pressed. Now add
    InstallApplicationEventHandler(&myHotKeyHandler,1,&eventType,NULL,NULL);
this installs our event handler method we declared earlier, but haven't implemented yet, so when this event happens it will call our code. Now we need to uniquely identify our hotKey...
    myHotKeyID.signature='mhk1';     myHotKeyID.id=1;
If you just intend on having only 1 global keyboard shortcut then this doesn't matter too much, but if you intend on having multiple global keyboard shortcuts then the id will matter greatly, it's what you will use to uniquely identify each specific event in the method we will implement shortly.
    RegisterEventHotKey(49, cmdKey+optionKey, myHotKeyID, GetApplicationEventTarget(), 0, &myHotKeyRef);
This is what actually registers our global shortcut. In Essence it's arguments are (1) the key code to the key you will use in combination with (2) modifier keys to create your global keyboard shortcut and (3) the Application Event Target which the GetApplicationEventTarget() method retrieves for us and finally (4) the EventHotKeyRef we declared earlier which gives us a reference to this keyboard shortcut we are registering. In this case it registers the spacebar (int 49) plus the command key and option key. So when Command+Option+Spacebar is hit our global keyboard shortcut will be triggered. It's important to note that you cannot register the same key combination twice within the same application and have it trigger both methods, however multiple applications can register for the same global keyboard shortcut and Carbon events will trigger events in both applications. I decided to test this by duplicating the keyboard shortcut I use for OmniFocus quick entry which for me is Control+Option+Space Bar
    RegisterEventHotKey(49, controlKey+optionKey, myHotKeyID, GetApplicationEventTarget(), 0, &myHotKeyRef);
and woola the OmniFocus quick entry Window and my event both triggered
multiple_apps_1_carbon_event.png
Now the hard part is behind us all we need to do is implement the method
OSStatus myHotKeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData) {     NSLog(@"YEAY WE DID A GLOBAL HOTKEY");          return noErr; }
What if we want to handle multiple global keyboard shortcuts?
OSStatus myHotKeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData) {     EventHotKeyID hkRef;     GetEventParameter(anEvent,kEventParamDirectObject,typeEventHotKeyID,NULL,sizeof(hkRef),NULL,&hkRef);          switch (hkRef.id) {         case 1:             NSLog(@"Event 1 was triggered!");             break;         case 2:             NSLog(@"Event 2 was triggered!");             break;     }          return noErr; }
Well then you have to use GetEventParameter() as such to get the EventHotKeyID which you can then get it's ID code and handle the event appropriately. This would also involve creating a 2nd hot key and setting it's id to 2, 3,etc.. Key Code The only thing left is the integer key code I mentioned earlier. I talked to Eric Rocasecca and Jim Turner from Startly (who make QuicKeys which I think would use Carbon Events, but evidently they use their own system) about this and they had a magazine with a reference of all the key codes in it, I didn't have this and didn't want to bother hunting down an old rare magazine. Several Google searches later I found an old app called AsyncKeys! which tells you the integer code of any key you press. I downloaded it a long time ago, but I did turn up a couple locations that actually had a download as the original site appears to be long gone (really sorry but I can only find .sit files): http://asynckeys.mac.findmysoft.com/ and if you Google around you can find other download locations. Here are some random key codes Spacebar 49 a = 0 1=18 F1 = 122 Left arrow = 123 Down arrow = 125 Right arrow = 124 Up Arrow = 126 Enter = 36 Backspace = 51 ` = 50 and I could go on and on... Conclusion Essentially we saw a brief intro into how Cocoa Events work, saw how carbon events work, installed an event handler in our application, registered a global hot key and saw how to handle multiple global hot keys. This is a narrow use scenario, not many apps will need to use this, but if you want to activate a particular function and your application is Cocoa and running in the background, this is the best way you achieve this functionality. I really wouldn't recommend digging into Carbon more as Apple is moving to deprecate it and as a Cocoa developer you should be finding that you'll need carbon less and less as time goes on.

 
...