Archive for the 'Cocoa' Category

Table view double-click actions

Monday, June 19th, 2006

It used to be that when you wanted to receive a double-click notification from an NSTableView, you had to do this in your -awakeFromNib:

[tableView setTarget:self];
[tableView setDoubleAction:@selector(doMagicThings:)];

Now, with the power of Bindings, you can do this in IB!

  1. Create an NSObjectController. Set its class name to the class of the desired receiver, and its “content” outlet (not binding) to the desired receiver.
  2. Bind the table view’s doubleClickTarget binding to the object controller. Controller key: content. Leave the model key path empty.
  3. Put the selector name in the field at the bottom of the binding view.

And a cheesy way that doesn’t involve a controller:

  1. Bind the table view’s doubleClickTarget binding directly to the receiver. Model key path: self.
  2. Put the selector name in the field at the bottom of the binding view.

UPDATE 2008-11-29: No need to add a -self method to your class or NSObject, as NSObject already has one. I think that the reason I didn’t see it before is because it’s declared in the NSObject protocol, not the NSObject class.

NSMovieView vs QTMovieView

Friday, June 2nd, 2006

I mentioned in my previous post that you should use QTMovieView rather than NSMovieView because QTMovieView is so much more efficient.

There is, however, one reason to use NSMovieView, and it’s the controller thumb:

A window with an NSMovieView, showing off its hourglass-shaped controller thumb.
NSMovieView with QuickTime 7.0.2.

A MoviePlayer 2.5.1 window, showing off QuickTime 6.0.3's controller thumb.
MoviePlayer 2.5.1 with QuickTime 6.0.3.

A window with a QTMovieView, showing off its plain round controller thumb.
QTMovieView with QuickTime 7.0.2.

Does anyone know how I can get QTMovieView to use the same controller thumb that NSMovieView and QuickTime 6 use?

And no, the “Speed” field and progress bar are not part of the QTMovieView.

UPDATE 2006-06-10: wootest says that the above is the editing controller, so you get it by making the movie editable. I’ve tried it and it works. The code is:

[movie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute];

Thanks!

Technorati tags: .

Enhancing QuickTime performance

Friday, June 2nd, 2006

I use a 450 MHz G4 Cube, so I tend to look hard at minimizing any large drains on my CPU. Such drains include playback of large video files (such as the 540p version of MacBreak). So I’ve been experimenting on and off with faster ways of playing back QuickTime movies. Here are my findings.

First, do not use NSMovieView. In my app, the NSMovieView used 50% of my CPU at all times — even when the movie was paused. Bad, bad, bad. And the frame rate sucked, too. (UPDATE 23:50 PDT: It seems like NSMovieView simply draws the entire frame periodically and unconditionally. The CPU usage changed based on the size of the window.) When I replaced it with QTMovieView, the CPU usage went way down, and the frame rate became watchable.

Second, Apple has a document called Enhancing Movie Playback Performance. Read it, learn it, live it.

Some of its information bears expanding-upon, though:

  • These are basic QuickTime functions, not QTKit. Both NSMovie and QTMovie allow you to get the raw QuickTime Movie, which you pass to these functions.

  • Prerolling actually involves two steps. First, call PrePrerollMovie. (No, I am not making this up.) Then, call PrerollMovie.

  • Remember MoviePlayer? It had two checkboxes for enhancing speed:

    Screenshot of MoviePlayer's Info window for a MacBreak episode, showing the “video_main” track, Preload options.

    Preload is obvious; it corresponds to LoadMovieIntoRam. Cache hint is not so obvious; what it does is keep movie data in RAM after it has been played (for looping). This corresponds to the keepInRam option to LoadMovieIntoRam.

    If you use keepInRam, be sure to call LoadMovieIntoRam with the unkeepInRam and flushFromRam options when you’re done with the movie, so that the memory used will be freed.

    Note that in MoviePlayer, you could only set preload options per-track (there was a “Movie” category, but you could not set preload options for it). So this actually corresponds to LoadTrackIntoRam. I find LoadMovieIntoRam more useful for my situation; obviously, you should use whichever one of LoadMovieIntoRam, LoadTrackIntoRam, or LoadMediaIntoRam is appropriate for yours.

  • Preloading all of a movie is very expensive, especially if the movie is large (MacBreak takes about 20 seconds to load — that’s forever in user time). Use it only if you have to, and show a progress indicator if you do. If you can, preload sections at a time — I might, for example, load 30 seconds every 1 second starting from file open.

Third, I suggest making sure that your QTMovieView is set to preserve aspect ratio. I don’t know whether aspect ratio distortion has a negative effect on QT performance — especially if the movie is being scaled anyway — but having this turned on can’t hurt.

Technorati tags: , .

Beware the nib

Sunday, May 7th, 2006

Say you have an object, X, and a nib containing two other objects, Y and Z. X has two outlets, y and z, with typical accessors for each.

X, or another object on behalf of X, loads the nib with X as its owner. NSNib, naturally, sets the y and z properties of X to the two objects in the nib, using the accessors since they exist.

Now, when an object is instantiated, it has a retain count of 1; it is implicitly owned by the object that created it. If you release that object, the retain count goes down to 0 and the object dies.

Such is the case of the objects Y and Z when they are unarchived from the nib: After they come out of deep freeze, they have that starting retain count of 1. But then they are passed to the accessors of X, which, if written in the usual way, retain Y and Z. Now the retain counts are 2 each.

When X is finished with Y and Z, it releases them, of course (perhaps by calling its accessors with nil). But the implicit retains still exist. Therefore, so do Y and Z.

This isn’t a nib bug, though; the bug is in X. Outlets aren’t supposed to be retained. So, if you do implement accessors, they should be non-retaining. Or, if you can, omit the accessors; NSNib will do the Right Thing for you.

Example of the bug: NibLeak (source code with Xcode 2.2.1 project).

Technorati tags: .

Making vim grok Obj-C

Monday, April 24th, 2006

Like many, I use the popular open-source text editor vim. Earlier, I set about making it more usable through syntax coloring. This included tweaking its support for Objective-C.

First, mkdir ~/.vim, and cd ~/.vim. Now mkdir syntax. cp /usr/share/vim/vim62/filetype.vim . and cp /usr/share/vim/vim62/syntax/objc.vim syntax/. Then select and copy this patch:

Index: filetype.vim
===================================================================
--- filetype.vim 2005-03-21 02:12:47.000000000 -0800
+++ filetype.vim 2006-04-24 03:33:27.000000000 -0700
@@ -262,7 +262,7 @@
 
 " .h files can be C or C++, set c_syntax_for_h if you want C
 au BufNewFile,BufRead *.h
- \ if exists("c_syntax_for_h") | setf c | else | setf cpp | endif
+ \ if exists("c_syntax_for_h") | setf c | else | if exists("objc_syntax_for_h") | setf objc | else | setf cpp | endif | endif
 
 " TLH files are C++ headers generated by Visual C++'s #import from typelibs
 au BufNewFile,BufRead *.tlh   setf cpp
Index: syntax/objc.vim
===================================================================
--- syntax/objc.vim 2005-03-21 02:12:49.000000000 -0800
+++ syntax/objc.vim 2006-04-24 03:19:25.000000000 -0700
@@ -43,6 +43,8 @@
 syn match  objcDirective "@class\|@end\|@defs"
 syn match  objcDirective "@encode\|@protocol\|@selector"
 
+syn keyword     objcStorageClass   in out inout byref bycopy
+
 " Match the ObjC method types
 "
 " NOTE: here I match only the indicators, this looks
@@ -73,6 +75,7 @@
   HiLink objcFactMethod Function
   HiLink objcStatement Statement
   HiLink objcDirective Statement
+  HiLink objcStorageClass StorageClass
 
   delcommand HiLink
 endif

Now type pbpaste | patch -p0.

OK, now you have modified copies of the file type detector and the Obj-C syntax coloring. Now you need a .vimrc. If you already have one, add this to it; otherwise, create it with this:

let c_gnu=1
let c_no_bracket_error=1
let objc_syntax_for_h=1
syntax enable

This makes the following changes:

c_gnu
Enables detection of some GCC extensions to C.
c_no_bracket_error
Allows {} inside of []. This lets you do compound literals inside messages; for example: [self setFrame:(NSRect){ NSZeroPoint, (NSSize){ 128.0f, 128.0f } }];
objc_syntax_for_h
Tells vim (with my modifications, that you did above) that a .h file is an Obj-C header, not a C++ header.
syntax enable
Enables syntax-highlighting.

Technorati tags: , .

Report-an-Apple-bug Friday! 34

Friday, April 21st, 2006

This bug is Xcode: Cocoa Document-Based Application template uses old-style document methods. It was filed on 2006-04-21 at 21:19 PDT.


Summary:

NSDocument documentation recommends using -readFromData:ofType:error: and -dataOfType:error:, but the project template uses the older methods.

Steps to Reproduce:

  1. Create a new project.
  2. Use the Cocoa Document-Based Application template.

Expected Results:

MyDocument, from the new document, implements -readFromData:ofType:error: and -dataOfType:error:.

Actual Results:

MyDocument implements the deprecated methods -loadDataRepresentation:ofType: and -dataRepresentationOfType:.

Regression:

Prior to Mac OS X 10.4, this wasn’t a problem, because -loadDataRepresentation:ofType: and -dataRepresentationOfType: were not deprecated.

Notes:

One could make the argument that the deprecated methods should still be implemented so that the new application is compatible with 10.3.x and earlier. But a new application is not likely to require such compatibility. Also, if this argument is indeed the motivation, then the project should target the 10.3 (or an earlier) SDK.


Technorati tags: , .

Report-an-Apple-bug Friday! 29

Friday, April 14th, 2006

This bug is NSWorkspace documentation contains two split sentences. It was filed on 2006-04-14 at 23:30 PDT.


Summary:

Documentation of several instance methods of NSWorkspace contains two sentences that have each been split in two, with the method signature between.

Steps to Reproduce:

  1. Go to the NSWorkspace documentation.
  2. Visit -activeApplication or -launchedApplications.

Expected Results:

Both sentences are not split.

Actual Results:

Both sentences are split.

Regression:

None.

Notes:

None.


Technorati tags: , .

Report-an-Apple-bug Friday! 28

Friday, April 14th, 2006

This bug is NSAnimation documented as inheriting from itself. It was filed on 2006-04-14 at 23:25 PDT.


Summary:

The infobox at the top of the NSAnimation reference gives a cyclic inheritance path.

Steps to Reproduce:

  1. Go to the NSAnimation reference.

Expected Results:

The infobox at the top says that NSAnimation inherits from NSObject.

Actual Results:

The infobox at the top says that NSAnimation inherits from NSAnimation inherits from NSObject.

Regression:

None known.

Notes:

As documented, NSAnimation inherits from both itself and NSObject. This is both cyclic inheritance and multiple inheritance, and both are illegal in Objective-C.

Similar to “NSViewAnimation documentation documented as inheriting from itself.”.


Technorati tags: ,

Report-an-Apple-bug Friday! 27

Friday, April 14th, 2006

This bug is NSViewAnimation documented as inheriting from itself. It was filed on 2006-04-14 at 23:21 PDT.


Summary:

The infobox at the top of the NSViewAnimation reference gives a cyclic inheritance path.

Steps to Reproduce:

  1. Go to the NSViewAnimation reference.

Expected Results:

The infobox at the top says that NSViewAnimation inherits from NSAnimation inherits from NSObject.

Actual Results:

The infobox at the top says that NSViewAnimation inherits from NSViewAnimation inherits from NSAnimation.

Regression:

None known.

Notes:

As documented, NSViewAnimation inherits from both itself and NSAnimation. This is both cyclic inheritance and multiple inheritance, and both are illegal in Objective-C.

Also, NSAnimation is the last (highest) in the list, rather than NSObject, which means that NSAnimation is a root class.


Technorati tags: , .

Report-an-Apple-bug Friday! 26

Friday, April 14th, 2006

This bug is NSViewAnimation documentation lists effect values among animation-option keys. It was filed on 2006-04-14 at 23:15 PDT.


Summary:

The Constants section of the NSViewAnimation reference lists the two effect values among the animation-option keys.

Steps to Reproduce:

  1. Go to the NSViewAnimation reference.
  2. Go to the Constants section.

Expected Results:

The effect values, NSViewAnimationFadeInEffect and NSViewAnimationFadeOutEffect, have a separate table from the option keys (such as NSViewAnimationEffectKey, the key for which the two *Effect constants are legal values).

Actual Results:

NSViewAnimationFadeInEffect and NSViewAnimationFadeOutEffect are listed in the same table with the option keys.

Regression:

None known.

Notes:

None.


Technorati tags: ,

New Cocoa docs!

Tuesday, March 21st, 2006

The Cocoa documentation was completely redesigned this month. Class docs are now whole sections, rather than a single page each, and each such section now has the same look and feel as a Carbon Manager’s docs. Check it out:

My favorite feature of the new design is that the class names are no longer in two columns. The two-column design was theoretically a good idea, because it meant that the page was shorter (which would ordinarily mean less scrolling), but bad in practice because it means you have to look in both columns to find a class (especially if its name is near the middle of the alphabet, like the NSMutableFoo classes are — there were some of those in each column in the old design).

You can copy these docs to your own machine by going to Xcode’s Preferences, Documentation pane, and clicking “Check Now”.

Technorati tags: ,

Report-an-Apple-bug Friday! 11

Friday, March 17th, 2006

This bug is -[NSMenu menuBarHeight] always returns 0.0f. It was filed on 2006-03-17 at 23:55.

UPDATE 2006-03-25: Uploaded test app to GeoCities.


Summary:

NSMenu‘s -menuBarHeight method always returns 0.0f. Even the main menu’s.

Steps to Reproduce:

  1. Call [[NSApp mainMenu] menuBarHeight].

Expected Results:

The method returns 22.0f.

Actual Results:

The method returns 0.0f.

Regression:

None known.

Notes:

Appearance Manager (in the form of the GetThemeMenuBarHeight function) and NSMenuView (in its +menuBarHeight method) both return 22.0f, the correct height of the menu bar under Tiger.

The documentation for +[NSMenuView menuBarHeight] recommends using -[NSMenu menuBarHeight] instead.

This method is superseded in Mac OS X v10.4 by the NSMenu menuBarHeight instance method.

Following this advice would break one’s app on 10.4.3 through 10.4.5 (the bug exists on 10.4.5 as well).

The bug works with any menu — the main menu isn’t the only one. It’s just the most obvious menu to call that method on.

Workarounds:

Use GetThemeMenuBarHeight or +[NSMenuView menuBarHeight].


Technorati tags: , .

New Apple documentation

Wednesday, March 8th, 2006

I don’t ordinarily write about changes to Apple’s documentation, since you can get that info straight from ADC RSS, but today’s round of changes is unusually significant.

Apple replaced several of the documents relating to Cocoa with new ones, and added some things to the new ones as well. the full run-down:

Was Now
  • Basic Drawing
  • Drawing and Images
  • The Drawing Environment
  • OpenGL
Cocoa Drawing Guide
  • What Is Cocoa?
  • Cocoa Objects
  • Adding Behavior to a Cocoa Program
  • Cocoa Design Patterns
  • Communicating With Objects
Cocoa Fundamentals Guide

Two new chapters have been added: “The Core Application Architecture” and “Other Cocoa Architectures”. In addition, the discussion of the Model-View-Controller design pattern in “Cocoa Design Patterns” has been greatly expanded.
revision history

  • Sdef Scriptability Guide for Cocoa
  • Scriptable Application Programming Guide for Cocoa
Cocoa Scripting Guide
Document-Based Applications Document-Based Applications Overview

New articles added are “Message Flow in the Document Architecture”, “Creating Multiple-Document-Type Applications”, “Autosaving in the Document Architecture”, and “Error Handling in the Document Architecture”.
revision history

Drawing and Views Scroll View Programming Guide for Cocoa
Drawing and Views View Programming Guide for Cocoa

I think the new set of documents may be much more suitable for passing to people who are learning for the first time. I’ll show The_Tick, who’s learning Cocoa, and see what he thinks.

while I’m at it, I’ll point out that they clarified the docs on CGImageSourceUpdateData:

Each time you call the function CGImageSourceUpdateData, the data parameter must contain all of the image file data accumulated so far.

so you should probably use a CFMutableData (or its NS equivalent) when using this function.

A patch for IconFamily to support FSRefs

Monday, January 30th, 2006

the current release version of Troy Stephens‘s IconFamily class, 0.5.1, uses FSSpec for all I/O. I updated it in July 2005 to use FSRef instead, and also fixed a memory leak and cleaned up a few minor code details. on 2005-07-19, I emailed the patch and a changelog to Troy Stephens.

so far, he has not applied the patch (or at least not put it on his website), nor has he even responded to my email. AFAIK, he simply threw it away (or never received it in the first place). I have the email archived, but I took no further action.

today, a user on IRC msged me and said that he had heard that I had written this, and he asked me for a copy. so I have zipped up the patch and the changelog (removing my ancient, recently-defunct email address from it), and posted it on my website. enjoy the IconFamily FSRef patch.

UPDATE 2006-08-26: IconFamily 0.9.1 and later have the patch built in. You don’t need the patch if your copy of IconFamily is up-to-date.

Have you seen this crash?

Sunday, January 29th, 2006

Here’s one I ran into while writing BZ Soundboard.

#0 0x9073fba4 in CFRetain () #1 0x92964b60 in _NSKeyValueObservationInfoCreateByRemoving () #2 0x92964938 in -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] () #3 0x92964828 in -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] ()

I solved this one on a hunch — that the NULL being CFRetained (print $r3 in gdb to see the first function argument) was the result of some kind of lookup with the proposed ex-observer as the key. If the ex-observer was not actually observing anything, the lookup would return nil or NULL, and apparently that result is not checked before it is passed to CFRetain.

Executive summary: If you get this crash, it means that you were not actually observing anything (or at least not that key path).

Report-an-Apple-bug Friday! #2

Friday, January 27th, 2006

I submitted a new bug: NSFileManager does not accept NSString values for HFS types. it follows, edited only for HTMLification.


Summary:

from the NSFileManager documentation:

The following keys access file attribute values contained in NSDictionary objects used by changeFileAttributes:atPath:, fileAttributesAtPath:traverseLink:, createDirectoryAtPath:attributes:, and createFileAtPath:contents:attributes::

NSFileHFSCreatorCode
NSNumber containing an unsigned long (see “HFS File Types”)
NSFileHFSTypeCode
NSNumber containing an unsigned long (see “HFS File Types”)

Steps to Reproduce:

/*1*/ NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys: NSFileTypeForHFSTypeCode('FOO!'), NSFileHFSTypeCode, NSFileTypeForHFSTypeCode('BAR!'), NSFileHFSCreatorCode, nil]; /*2*/ [[NSFileManager defaultManager] createFileAtPath:@"strings are our friends.txt" contents:[NSData data] attributes:attrs];

Expected Results:

the file is successfully created and imbued with both of the desired attributes.

Actual Results:

NSString throws an exception because it does not respond to -unsignedLong (yes, I know I got this selector wrong when I filed it — oops —ed), as assumed by NSFileManager.

Regression:

none known.

Notes:

NSFileTypeForHFSTypeCode appears to be the canonical way to create, effectively, an ‘instance’ of an HFS file type to be passed around in Cocoa, but NSFileManager only accepts NSNumbers. NSNumber seems to me to be more of a ‘raw’ representation. besides which, this usage of it definitely assumes the length of an unsigned long.