Earlier this evening I put together a convenient little class, ViewOptions, that allows you to toggle the columns on a table view. Here’s what it looks like:


Requires Mac OS X 10.5.
Download!

Usage is simple:

[[ViewOptions viewOptions] showViewOptionsForTableView:oYourTableView];

And thats really all there is to it.

Update 9/3/08: I just fixed a fatal design flaw that prevent this class from working properly: Because selection was disabled it was impossible to toggle the checkboxes.

You are free to use, modify, and distribute the above code in binary or source without restrictions, provided that you understand the creator is not liable in any size, shape, or form.

by Peter on 08/19/2008, in Cocoa, Random, Software, 0 comments

Due to a recent email, it came to my attention that the zip containing the IKImageFlowView sample I wrote on my sample code page was completely botched and unexpandable. So I set out to rebuild the project and produce a (some-what) fully documented header for IKImageFlowView. The header is included in the project, and for the sake of prosperity I am posting the contents here:

/*

* IKImageFlowView.h

* Documentation Copyright (c) 2008, Peter MacWhinnie. All Rights Reserved.

* (Some documentation directly stolen from IKImageBrowserView, what, I am lazy)

*

* Generated by class-dump 3.1.2.

* class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2007 by Steve Nygard.

*/

#import <Cocoa/Cocoa.h>

#import <ImageKit/ImageKit.h>

typedef NSUInteger IKImageFlowAnimationsMask;

/*!

@class IKImageFlowView

@abstract The IKImageFlowView class is used to represent a set of images in a cover flow.

@discussion The documentation in this file is far from complete, but should give you

enough information to have a basic understanding of how to use IKImageFlowView.<br />

This view requires Mac OS X 10.5+ and that you link Quartz or ImageKit.

*/

@interface IKImageFlowView : NSOpenGLView

{

id _dataSource;

id _dragDestinationDelegate;

id _delegate;

void *_reserved;

}

/*!

@method flowViewIsSupportedByCurrentHardware

@abstract Returns YES if cover flow is supported by the current hardware; NO otherwise.

*/

+ (BOOL)flowViewIsSupportedByCurrentHardware;

/*!

@method reloadCellDataAtIndex:

@abstract Marks a specified row as needing reloading.

*/

- (void)reloadCellDataAtIndex:(NSInteger)index;

/*!

@method reloadData

@abstract Marks the receiver as needing its data reloaded.

*/

- (void)reloadData;

/*!

@method itemAtIndexIsLoaded:

@abstract Returns YES if the item at the specified index is loaded; NO otherwise.

*/

- (BOOL)itemAtIndexIsLoaded:(NSUInteger)index;

/*!

@property animationsMask

@abstract The animations mask used by the receiver.

@discussion No further information available for this property,

if you have any an email would be appreciated.

*/

@property IKImageFlowAnimationsMask animationsMask;

/*!

@property selectedIndex

@abstract The index of the selected item in the receiver.

*/

@property NSUInteger selectedIndex;

/*!

@property focusedIndex

@abstract The index of the focused item in the receiver.

@discussion If you have more information about this method, an email would be appreciated.

*/

- (NSUInteger)focusedIndex;

/*!

@method cellIndexAtLocation:

@abstract Returns the index of the cell at the specified point.

*/

- (NSUInteger)cellIndexAtLocation:(NSPoint)point;

/*!

@method cellIndexAtPosition:

@abstract Returns the index of the cell at the specified position.

*/

- (NSInteger)cellIndexAtPosition:(CGFloat)position;

/*!

@method countOfVisibleCellsOnEachSide

@abstract The number of cells visible on the left and right side of the selected item.

*/

- (NSInteger)countOfVisibleCellsOnEachSide;

/*!

@method flipCellsWithOldSelectedIndex:newSelectedIndex:

@abstract No information available for this method.

*/

- (void)flipCellsWithOldSelectedIndex:(NSUInteger)oldSelectedIndex newSelectedIndex:(NSUInteger)newSelectedIndex;

/*!

@method updateLayoutInRange:

@abstract No information available for this method.

*/

- (void)updateLayoutInRange:(NSRange)range;

/*!

@method updateLayout

@abstract No information available for this method.

*/

- (void)updateLayout;

/*!

@method selectedImageFrame

@abstract Returns the frame of the selected item.

*/

- (NSRect)selectedImageFrame;

/*!

@property showSplitter

@abstract Whether or not to show the splitter in the image flow view.

*/

@property BOOL showSplitter;

/*!

@property delegate

@abstract The delegate of the receiver.

*/

@property (assign) id delegate;

/*!

@property dataSource

@abstract The data source of the receiver.

*/

@property (retain) id dataSource;

/*!

@property zoomOnSelectedLayer

@abstract Whether or not the receiver zooms on the selected item.

*/

@property BOOL zoomOnSelectedLayer;

/*!

@method backgroundIsLight

@abstract Returns YES if the receivers background is light; NO otherwise.

*/

- (BOOL)backgroundIsLight;

/*!

@method backgroundIsBlack

@abstract Returns YES if the receivers background is black; NO otherwise.

*/

- (BOOL)backgroundIsBlack;

/*!

@property backgroundColor

@abstract The background color of the image flow view.

*/

@property (retain) NSColor *backgroundColor;

/*!

@property cellBackgroundColor

@abstract The cell background color of the image flow view.

*/

@property (retain) id cellBackgroundColor;

/*!

@property cellBorderColor

@abstract The cell border color of the image flow view.

*/

@property (retain) NSColor *cellBorderColor;

/*!

@property imageAspectRatio

@abstract The image aspect ratio used by the receiver.

*/

@property CGFloat imageAspectRatio;

/*!

@property cellsAlignOnBaseline

@abstract Whether or not the receiver aligns its cells on its baseline.

*/

@property BOOL cellsAlignOnBaseline;

//These methods are no-ops, so there is no information available on them.

- (id)thumbnailImageAtIndex:(NSInteger)fp8;

- (id)previewImageAtIndex:(NSInteger)fp8;

@end

/*!

@protocol IKImageFlowViewDataSource

@abstract The IKImageBrowserDataSource formal protocol declares the methods that an instance

of the IKImageFlowView class uses to access the contents of its data source object.

*/

@protocol IKImageFlowViewDataSource

@required

/*!

@method numberOfItemsInImageBrowser:

@abstract Returns the number of records managed by the data source object.

@param sender An image flow view.

@returnValue The number of records managed by the image flow view.

*/

- (NSUInteger)numberOfItemsInImageFlow:(IKImageFlowView *)sender;

/*!

@method imageFlow:itemAtIndex:

@abstract Returns an object for the item in an image flow view that corresponds to the specified index.

@param sender An image flow view.

@param index The index of the item you want to retrieve.

@returnValue An IKImageBrowserItem object.

*/

- (id)imageFlow:(IKImageFlowView *)sender itemAtIndex:(NSInteger)index;

@optional

/*!

@method imageFlow:writeItemsAtIndexes:toPasteboard:

@abstract Signals that a drag should begin.

@param sender An image flow view.

@param indexes The indexes of the items that should be dragged.

@param pasteboard The pasteboard to copy the items to.

@returnValue The number of items written to the pasteboard.

@discussion This method is optional. It is invoked after Image Kit determines

that a drag should begin, but before the drag has been started.

*/

- (NSUInteger)imageFlow:(IKImageFlowView *)browser writeItemsAtIndexes:(NSIndexSet *)indexes toPasteboard:(NSPasteboard *)pasteboard;

/*!

@method imageFlow:removeItemsAtIndexes:

@abstract Signals that a remove operation should be applied to the specified items.

@param sender An image flow view.

@param indexes The indexes of the items that should be removed.

@discussion This method is optional. It is invoked by the image browser after Image Kit

determines that a remove operation should be applied. In response, the

data source should update itself by removing the specified items.

*/

- (void)imageFlow:(IKImageFlowView *)sender removeItemsAtIndexes:(NSIndexSet *)indexes;

@end

/*!

@protocol IKImageFlowViewDelegate

@abstract The IKImageFlowViewDelegate is an informal protocol for the delegate of

an IKImageFlowView object. You can implement these methods to perform custom

tasks when in response to events in the image browser view.

*/

@protocol IKImageFlowViewDelegate

@optional

/*!

@method imageFlow:cellWasDoubleClickedAtIndex:

@abstract Performs custom tasks when the user double-clicks an item in the image flow view.

*/

- (void)imageFlow:(IKImageFlowView *)sender cellWasDoubleClickedAtIndex:(NSInteger)index;

/*!

@method imageFlow:cellWasDoubleClickedAtIndex:

@abstract Performs custom tasks when the user clicks an item in the image flow view.

*/

- (void)imageFlow:(IKImageFlowView *)sender didSelectItemAtIndex:(NSInteger)index;

@end

by Peter on 08/14/2008, in Cocoa, Software, 0 comments

In the process of a chat, the basic rules of cocoa memory management came up. This led me to make a list of the basic rules, which I’ve decided to post here for no particular reason. I don’t claim this list is particularly perfect, but I think its a pretty good attempt.

  • Objects instantiated by nibs (views, controllers, the likes) are automagically released when your application terminates
  • If you use a convenience constructor, like + NSString#stringWithFormat:, the value is autoreleased and doesn’t need to be explicitly released. In fact, if you release an object with a retain count of 1 thats been autoreleased, you’ll get a runtime error.
  • If you’re creating a lot of autoreleased objects, say in a loop, its best to create and drain an autorelease pool in the loop or around the loop to prevent unnecessary memory use.
  • Any time you allocate and initialize something, you need to balance it with a release. If you’re returning a new object in an accessor, you should autorelease it. Note: its really bad practice to autorelease objects that you could easily release a few lines later, it just adds to memory use.
  • Objects returned by accessors are either autoreleased, or owned by the receiver itself unless explicitly marked otherwise.
  • If you don’t start your application with NSApplicationMain, or you’ve spawned a new thread, you need to create an autorelease pool before anything you do, and you need to drain it when you’re done. If you don’t create an autorelease pool, you will receive an error message and will leak memory.

If you happen to be lazy, and don’t care about leaks beyond your control, you can in fact use garbage collection in 10.5 and up. Cocoa garbage collection is very far from transparent, and only works automatically for cocoa objects and nothing else. Here are a few things to keep in mind when using garbage collection:

  • CoreFoundation objects are not managed by the garbage collector. Even though it would make _a lot_ of sense, CFObjects are not automatically managed by the cocoa garbage collector even though they are internally the same as NSObjects. This means that using any CF* method that returns a new object must be released appropriately.
  • Just because you use garbage collection, doesn’t mean you shouldn’t write regular memory management code, even if its no-op. In the event you need to use some code you’ve written on a system older then leopard, or you just find that you don’t like garbage collection and its ugly overheads, this will in fact come quite in handy.
  • References don’t really just go away. As long as you have a reference to an object, be it an ivar, a regular variable, or in a collection the object will _never_ be destroyed which will result in a leak. Theoretically this should solve itself, but there are times when it doesn’t. If two objects are referencing each other, neither will ever be destroyed.

I wouldn’t say this is a definitive guide, its really just observations from experience. I don’t claim 100% accuracy, I am only human, and only writing this blog post as a passing fancy. But, if this can help someone[s], then thats great.

by Peter on 08/06/2008, in Cocoa, Software, 0 comments

The other day I decided to class-dump QTKit in hopes that QTMovie would have a real update-in-place method [1]. Well first of all, class-dump doesn’t work with 64 and 32 bit universal binaries so I didn’t actually use class-dump but rather o-tool [2].
Unfortunately QTKit doesn’t have some hidden update-in-place method. But! that isn’t to say it doesn’t have a bunch of really useful stuff that should be public for the sake of mine, and as a result everyone else’s sanity.
The following are just a few of the hidden methods, they’re simply the ones I found the most immediately useful.

@property float treble;
@property float bass;

The treble and bass properties do exactly what you think they do, they change the bass and treble levels on the receiving movie. The value scale is (oddly) between -8.0 and 8.0, 0.0 being default.

@property float balance;

Balance, just like the treble and bass properties, does exactly what you think it does. The value scale is between -1.0 and 1.0, 0.0 being default.

@property float gain;

I can’t say I am entirely sure about this property, it appears to be an alias for volume. The value scale is 0.0 to 1.0, 1.0 being default.

- (BOOL)isDRMAuthorized;
- (BOOL)isDRMProtected;

By far the most amusing of the hidden methods. I could see this being fairly useful.

@property BOOL saveable;

As far as I can tell this is just a convenience method that doesn’t really seem to do anything all that useful.

@property (copy) NSDictionary *annotations;

This has to be the most useful of the properties I found. ‘annotations’ is dictionary which contains all of the metadata associated with the file you’ve loaded into a QTMovie.

@property (copy) NSString *copyright;

This is likely another convenience method, the same information is available thru -attributeForKey: if you don’t feel like using private methods.

There we plenty of other private methods, many of which were convenience methods. The list above is simply of the methods I found immediately useful, there are dozens more.
If you wish to view the dump in its entirety the dump file is available here [3].


[1]: Yes, I am aware of -updateMovieFile, it doesn’t work for anything other then MOV files.
[2]: Okay, if you hadn’t guessed by now I dumped QTKit on Leopard.
[3]: Code dump generated with “otool -o -V /System/Library/Frameworks/QTKit.framework/Versions/A/QTKit > QTKit.dump”.

by Peter on 05/08/2008, in Cocoa, Software, 0 comments
Copyright © 2007-2008, Peter MacWhinnie. All Fancy Rights Reserved. Boring ones too.