Tuesday, February 14, 2012

VideoBuffet 1.0.2 released on the Mac App Store

Note: This blog is deprecated. @synthesize zach has moved to a new home, at zpasternack.org. This blog entry can be found on the new blog here. Please update your links.

This is a minor update, basically bug fixes. However, we did take the opportunity to convert it to Automatic Reference Counting (ARC). It really was as easy as it looked in the ARC WWDC session.

I highly recommend watching that video if you're considering moving to ARC, as well as reading the Transitioning to ARC Release Notes, and the llvm ARC page. Bookmark that last page, because though it might be rough reading all the way through, it's a very handy reference.

I had planned on posting some tips and tricks regarding converting to ARC, but truthfully, I don't have any. It was simple, and pretty much just worked.

Saturday, January 28, 2012

PuzzleTiles for Mac 1.1

Note: This blog is deprecated. @synthesize zach has moved to a new home, at zpasternack.org. This blog entry can be found on the new blog here. Please update your links.

PuzzleTiles for Mac 1.1 is now available on the Mac App Store. Check out the app page, or buy it now.

Friday, January 20, 2012

VideoBuffet 1.0.1 released

Note: This blog is deprecated. @synthesize zach has moved to a new home, at zpasternack.org. This blog entry can be found on the new blog here. Please update your links.

VideoBuffet 1.0.1 is now available in the Mac App Store. It's a minor update, which adds one new feature, and fixes several annoying bugs. Release Notes are here. If you haven't checked out VideoBuffet yet, do so. We think it's great.

Thursday, December 15, 2011

VideoBuffet now available

Note: This blog is deprecated. @synthesize zach has moved to a new home, at zpasternack.org. This blog entry can be found on the new blog here. Please update your links.


<shameless plug>
VideoBuffet, Fat Apps' QuickTime movie browser and player, is now available on the Mac App Store.  Check it out, or buy it now.
<shameless plug>

Wednesday, November 16, 2011

Don't invalidate your NSTimer in dealloc

Note: This blog is deprecated. @synthesize zach has moved to a new home, at zpasternack.org. This blog entry can be found on the new blog here. Please update your links.

Seasoned Cocoa developers may snicker at the title of this post, because it's probably obvious to them. It should have been obvious to me, but it wasn't. Maybe I can save someone some head-scratching by relaying my tale.

NSTimers retain their target. Now, I've been around the Cocoa block a few times, so I knew this to be the case (the docs state it explicitly), but I clearly hadn't thought through the ramifications. Walk with me for a minute.

Let's say you have a window, MainWindow, and a controller class for it, MainWindowController. You put a timer on it to periodically do some stuff. It might look like this:


@interface MainWindowController : NSWindowController
{
NSTimer* myTimer;
}
- (void) doSomeStuff;
@end

@implementation MainWindowController

- (id) initWithWindow:(NSWindow*)window
{
self = [super initWithWindow:window];
if( self ) {
const NSTimeInterval timerInterval = 10.0f;
myTimer = [NSTimer scheduledTimerWithTimeInterval:timerInterval
target:self
selector:@selector(doSomeStuff)
userInfo:nil
repeats:YES];
}
return self;
}

- (void) dealloc
{
[myTimer invalidate], myTimer = nil;
[super dealloc];
}

- (void) doSomeStuff
{
NSLog( @"doing stuff" );
}

@end


Seems reasonable, no? It did to me. The problem is that, as the docs state, NSTimers retain their target. When you create that timer in initWithWindow:, it retains the window controller, which means dealloc will never be called. dealloc isn't called until the controller's retain count is zero, and until the timer invalidates (which will be never, on a repeating timer), the controller's retain count will never be zero.

The solution would be to invalidate the timer elsewhere, perhaps in windowWillClose: (of course, your controller must also be the window's delegate for that to happen).


- (void) windowWillClose:(NSNotification*)notification
{
[myTimer invalidate], myTimer = nil;
}


Another thing I'd like to mention is the use of retainCount for debugging purposes. I've found that brand new Cocoa programmers tend to rely way too much on retainCount to try to figure out their memory management issues. Cocoa pros, on the other hand, will tell you to never ever call retainCount. You can't get any useful information from it, some say, because you can't know who's retaining your objects.

I think the truth lies somewhere in between. The truth is, you should know who's retaining your objects, and why. Though retainCount shouldn't be the first thing you look to, it can be useful on occasion if it seems like things aren't working as you expect.

In my case, I observed that calling initWithWindowNibName: on my window controller was returning an object with a retainCount of 2, when I was expecting 1. From there it was a pretty short walk to get to "ok, my timer is created here, but it's invalidated in dealloc… oh, wait."

Thursday, September 29, 2011

Regarding first responders: make, don't become

Note: This blog is deprecated. @synthesize zach has moved to a new home, at zpasternack.org. This blog entry can be found on the new blog here. Please update your links.

Things That Were Not Immediately Obvious To Me, #27:

If you have a view which you wish to become first responder, do NOT call becomeFirstResponder on it; it doesn't actually make the view first responder. Instead, call NSWindow's makeFirstResponder:

The NSResponder doc says (emphasis mine):

Use the NSWindow makeFirstResponder: method, not this method, to make an object the first responder. Never invoke this method directly.


This was not immediately obvious to me. Moral of the story: always read the damn docs.

Recapping:

[self becomeFirstResponder]; // Nope, never do that.

[[self window] makeFirstResponder:self]; // That'll do, pig.


As a side note, the description of becomeFirstResponder says:

Notifies the receiver that it’s about to become first responder in its NSWindow.

and

The default implementation returns YES, accepting first responder status. Subclasses can override this method to update state or perform some action such as highlighting the selection, or to return NO, refusing first responder status.


OK, so can someone tell me why this method wasn't named shouldBecomeFirstResponder? Had that been the case, I wouldn't have had to resort to the docs to figure out why it wasn't doing what I thought it should do. Just sayin'.


Tuesday, August 16, 2011

PuzzleTiles on sale

Note: This blog is deprecated. @synthesize zach has moved to a new home, at zpasternack.org. This blog entry can be found on the new blog here. Please update your links.

<shameless plug>

For the next 48 hours, Fat Apps is giving away PuzzleTiles, PuzzleTiles HD, and PuzzleTiles/Mac for free.  Grab 'em while you can!

</shameless plug>