Stepwise  
Cocoa Starting Point - Articles - News - Site Map - Search - Status - Comments  

 

Mac OS X Hidden Secrets Revealed

Newcomers to Apple's new technologies sometimes wonder at the productivity of the ex-NeXT users -- and in particular developers -- and ask themselves how is it possible that these people are able to achieve so much with so little documentation. Finally we uncover the secrets. Class libraries, API and Preferences settings heretofore shared only be an elite few, exposed today for all.

User Defaults

A number of hidden preferences significantly enhance the Mac OS X user-experience for the cognoscenti.

defaults write com.apple.Preferences ExposeHiddenPreferences Yes
defaults write com.apple.installer TrashSymbolicLinks No
defaults write com.apple.finder UseCocoaFinder Yes
defaults write com.apple.finder RunSlowly No
defaults write com.apple.finder LoadedFolders Springy
defaults write com.apple.EOModeler CrashRandomly No
defaults write com.microsoft.Office SendPersonalInformationToMotherShip No

These overrides, though, are just the tip of the iceberg. It is really developers who gain the most advantage, from secret classes and methods covering a wide range of functionality.

Documentation

/Library/.SecretNeXTDeveloperDocumentation

This is where all the real (complete) Cocoa and WebObjects documentation is kept, the stuff that the NeXT developers referred to when they were learning about these technologies. Note in particular the SpoonFeeding subdirectory: it contains a set of applications to run on a variety of platforms which, given the right peripherals (available from NeCKS Implants Inc.), simply uploads the entire documentation to the developer's head without them having to read anything, or really exert any effort at all. A number of excerpts are reproduced below.


Compiler directives

The following compiler directives help to make the development environment easier to use:

--ucppsfc (Use C++ syntax for Cocoa)
--steewitontbu (Static typing everywhere except where it turns out not to be useful)
--dwimnwis (Do what I mean not what I said)


Cocoa Frameworks

The Image Manipulation framework

The answer to the perennial question, "Why didn't Apple provide Cocoa developers with a set of classes such that I could simply put an view in a window which would then give a wide range of professional bitmap-editing functionality, accessible from the widget set on an associated palette -- so that I can just create a nibware solution which I can sell for $699/seat?"

The CocoaUniversalImageManipulation.privateframework consists of just three classes.

NSLayeredImageView

This view provides a layered display of bitmaps in a wide variety of formats (TIFF, JPG, PSD, EPS...), and allows zoom from 25 to 1600%. In conjunction with the other classes in the framework, it offers a comprehensive image-editing tool.

NSUniversalImageManipulationPalette

This palette holds a single NSControl subclass, NSUniversalImageManipulation, which contains all the buttons, sliders, texfields etc. a user will require to perform a wide range of effects on bitmaps -- it includes, for example, a brush chooser, cropping tool, and effect selection browser.

NSArbitraryImageEffects

This is a controller object. It provides all the functionality require by the NSLayeredImageView. Simply instantiate one of these objects in your nib file and connect it to an instance of NSLayeredImageView and NSUniversalImageManipulation. If you connect the outlets incorrectly, NSArbitraryImageEffects will swap them for you.


Memory Management

Some developers seem to get memory management right, effortlessly. Concealed from all but the most seasoned veteran, the following API makes it easy:

NSZone

NSZones are able to perform a number of garbage collection routines to ensure that memory leaks do not occur.

doGarbageCollection:

+ (void)doGarbageCollection:(BOOL)aFlag

Sending YES as the argument to this class method switches on garbage collection. The developer is given more fine-grained control over garbage collection strategies, however, with the following method:


setGarbageCollectionType:

+ (void)setGarbageCollectionType:(NSGarbageCollectionType)aCollectionType

This method takes a single argument, which should be one of the following constants:

typedef enum {
		NSDuringIdleMoments
		NSInopportuneMoments
		NSWhenItWontInterfereWithRealTimeProcessing
		NSNowNowNow
		NSJavaModel // beta
		NSWhenHidden
		NSWednesdays
		NSWhenever
		NSAllOfTheAbove
} NSGarbageCollectionType

NSObject <NSMemoryManagementJedi> category

allocWithZone:andFreeWhenImDone:

+ (id)allocWithZone:(NSZone *)aZone andFreeWhenImDone:(BOOL)freeWhenDone
- (void)freeIfNotNeeded

These methods are used in conjunction with NSZone's garbage collection utilities. To make life even easier, if you don't want to use garbage collection, the freeIfNotNeeded method automatically determines whether or not an object is required, and frees it when it is no longer needed, irrespective of the number of retains and releases it is sent.


NSObject categories

<NSAcceptMisspelledSelectors>

This category implements two methods:

- (void)performMethodsUsingFuzzyMethodNameMatching:(NSFuzzyFactor)factor
- (void)performMethod:(SEL)aSelector accordingToWhatIWantedAsOpposedToTheCodeThatIActuallyWrote:(id)anObject

One of the more common errors made when writing delegate methods, and when using selectors, is to misspell a method or selector name. By sending an object a performMethodsUsingFuzzyMethodNameMatching: message, the runtime will automatically allow approximate matches to method names, with a tolerance factor:

typedef enum {
		NSOneCharacterOut
		NSCommonMisspellings
		NSQuiteClose
		NSInTheRightBallpark
		NSJustDoIt
} NSFuzzyFactor 

Thus, for example, if you have implemented a delegate method called windowSjouldClose:, and have previously called the delegate object's performMethodsUsingFuzzyMethodNameMatching: method with the NSFuzzyFactor set to NSOneCharacterOut, your method will be called when a windowShouldClose: message is sent.

Care should be taken using NSInTheRightBallpark and NSJustDoit, since these may have unfortunate side-effects -- for example, if a window's delegate is sent windowShouldClose:, and it implements windowSjouldClose: and wondowWillClasp:, both will be called. (They will be called in order of closeness to the correct method, based on a vector-matching algorithm from AIAT.) Instead, on Mac OS X 10.1.2 and above, you should consider using performMethod:accordingToWhatIWantedAsOpposedToTheCodeThatIActuallyWrote:. This has the additional benefit of determining if any arguments have been omitted, and supplying them as appropriate.


NSObject <NSBehaveAccordingToTheDocs> Category

This category implements a single class method:

behaveAsDocumented

+ (void)behaveAsDocumented

This ensures that the receiving class behaves as described by the documentation, not necessarily as implemented. Note: Care should be taken when using this method. If the class has any methods for which the documentation states "Description forthcoming", these will be replaced by no-ops.


NSView

drawRectReallyFast:

- (void)drawRectReallyFast:(NSRect)aRect

Normal display using drawRect: uses a set of fully-optimized drawing routines. drawRectReallyFast: uses hyper-optimized algorithms, and makes full use of any graphics accelerator cards installed. (It is anticipated that with Bluetooth the card will not even have to be installed on the user's system, just within Bluetooth's range.) Note that this method is not available if your application is linked against any Carbon frameworks.

See also: -drawRectReluctantly:howReluctant:

.


Notifications and delegate methods

NSNervousKernelNotification

This notification is sent by NSProcessInfo whenever the kernel is nervous, but before it actually panics. This allows the receiver of the notification to do things to minimize the likelihood of a kernel panic affecting its process.

Suggested reactions to this notification include unexpectedly quitting, or presenting the user with a nib file instantiated at random using the NSBundleAdditions class method loadRandomNibFileFromSomeOtherApplicationWithOwner: (id) owner.


NSApplication methods and delegate methods

unexpectedlyQuit

- (void)unexpectedlyQuit

This method will cause your application to unexpectedly quit. To ensure that the quit is truly an unexpected one, AppKit has extended the Objective-C compiler with a code obfuscation mechanism that encrypts the unexpectedlyQuit method symbol using a 128 bit, public key technique that makes the runtime unable to detect that the method call will actually cause the application to unexpectedly quit - even through reflection. The runtime actually thinks that the selector being executed is one of the following:

- (NSWorldPeace *)bringWorldPeace:(id)sender withLoveAndUnderstanding:(BOOL)aFlag
- (NSHamSandwich *)makeMe:(id)sender aHamSandwichWith:(NSSandwichTrimmings)theTrimmings

This makes the subsequent quit completely unexpected as it turns out that instead of getting a ham sandwich or world peace, the application crashes, leaving all involved confused and befuddled, with file handles and other system resources left open and all akimbo.

See Also: -applicationShouldUnexpectedlyQuit:, -applicationDidUnexpectedlyQuit:

The delegate method applicationShouldUnexpectedlyQuit: is useful, as implementing and returning NO can help greatly reduce debugging time.

The delegate method applicationDidUnexpectedlyQuit: is similarly useful, since the delegate of the application can restart the application after it has unexpectedly quit.

In conjunction with NSView methods such as drawRectReallyFast:, a developer can often have the delegate redraw the windows of the unexpectedly quit application before the system's "Application has unexpectedly quit" dialog box is presented to the user, thus making it seem that their system is throwing up random dialog boxes -- that have nothing to do with your software -- thereby diminishing the number of calls to your support line.


The NSInputManager notification

NSInputManagerUserDidSomethingParticularlyStupidNotification

This notification occurs when the user does something particularly stupid. A common use of this notification is to unexpectedly quit, just to teach the user a lesson. Depending on just how you feel about users of your application, you may choose to perform some other actions before unexpectedly quitting. These include NSFileHandle's -corruptFile, as illustrated below.

Common practice is to maintain a count of the number of times this notification is sent, and store the count in an application's user defaults. Many developers choose a zone in which to perform different tasks before unexpectedly quitting. Here is a code sample:

    NSFileHandle * applicationPreferences;  // assume these exist
    NSFileHandle * importantFile;
    int numberStupidActs;

    if (numberStupidActs > 1 && numberStupidActs < 10) {
        [applicationPreferences corruptFile];
        /*
         * Note that this method ensures that the
         * numberStupidActs count remains intact
         */
    }
    if (numberStupidActs > 10) {

        importantFile = [NSWorkspace fileContainingMostUrgentAndImportantData];
        [importantFile corruptFile];

    }

    [NSApp unexpectedlyQuit];

Different levels of file corruption may be specified using -corruptFileBy: and passing one of these values as the argument

typedef enum {
        NSOneBit
        NSChangePermissions
        NSChangeOwner
        NSDeleteResourceFork
        NSRandomizeFourBytes
        NSFUBAR
} NSFileCorruption


WebObjects

WOECommerce. privateframework

This is the answer to the perennial question, "Why didn't Apple provide WebObjects developers with a set of classes such that I could simply put my logo in the project, then link against a framework, and it would automatically start up, find out what database I'm using, figure out what the products are, how to present them to the customer in direct actions, provide a shopping cart which would immediately start a session, determine the customer's credit limit, do the whole SSL thing, and configure my web server and deployment for me so I can then charge my client $500,000 for figuring out how to add my logo in step 1?" This is the first of a series of D2W (Direct To Wallet) frameworks Apple has developed with the generous assistance of David K. Every.

Description forthcoming.


Enterprise Objects

Delegate methods

- (BOOL)editingContextShouldExhibitPuzzlingBehavior:(EOEditingContext *)anEditingContext

In EOF/Cocoa, substantial insights into the normal operation of database access can be achieved by creating a delegate for the editing context, and implementing:

- editingContextShouldExhibitPuzzlingBehavior:(EOEditingContext *)ec {
    return NO;
}
This method is deprecated in WebObjects5/Java.