블로그 이미지
Sunny's

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

'Code snippets'에 해당되는 글 1

  1. 2011.05.18 All The Quickies, Chronologically, Code Snippets
2011. 5. 18. 19:02 IPhone

  • Emacs registers (emacs->General) (17 May , 2011) [permalink]
    Emacs has a number of "registers", which you can treat as directly-addressable clipboards.

    Copy into register 1:

    1. select range
    2. M-x copy-to-register
    3. 1

    Paste from register 1:

    1. M-x insert-register
    2. 1

    View the contents of a register

    1. M-x view-register
    2. 1

    Register names can be single letters, numbers, characters. Upper and lower case are distinct.

  • Converting HSL to RGB (Graphics->General) (11 May , 2011) [permalink]
    // Based on Foley and van Dam algorithm.
    void ConvertHSLToRGB (const CGFloat *hslComponents, CGFloat *rgbComponents) {
        CGFloat hue = hslComponents[0];
        CGFloat saturation = hslComponents[1];
        CGFloat lightness = hslComponents[2];
    
        CGFloat temp1, temp2;
        CGFloat rgb[3];  // "temp3"
    
        if (saturation == 0) {
            // Like totally gray man.
            rgb[0] = rgb[1] = rgb[2] = lightness;
    
        } else {
            if (lightness < 0.5) temp2 = lightness * (1.0 + saturation);
            else                 temp2 = (lightness + saturation) - (lightness * saturation);
    
            temp1 = (lightness * 2.0) - temp2;
    
            // Convert hue to 0..1
            hue /= 360.0;
    
            // Use the rgb array as workspace for our "temp3"s
            rgb[0] = hue + (1.0 / 3.0);
            rgb[1] = hue;
            rgb[2] = hue - (1.0 / 3.0);
    
            // Magic
            for (int i = 0; i < 3; i++) {
                if (rgb[i] < 0.0)        rgb[i] += 1.0;
                else if (rgb[i] > 1.0)   rgb[i] -= 1.0;
    
                if (6.0 * rgb[i] < 1.0)      rgb[i] = temp1 + ((temp2 - temp1)
                                                               * 6.0 * rgb[i]);
                else if (2.0 * rgb[i] < 1.0) rgb[i] = temp2;
                else if (3.0 * rgb[i] < 2.0) rgb[i] = temp1 + ((temp2 - temp1)
                                                           * ((2.0 / 3.0) - rgb[i]) * 6.0);
                else                         rgb[i] = temp1;
            }
        }
    
        // Clamp to 0..1 and put into the return pile.
        for (int i = 0; i < 3; i++) {
            rgbComponents[i] = MAX (0.0, MIN (1.0, rgb[i]));
        }
    
    } // ConvertHSLToRGB
    

  • Converting RGB to HSL (Graphics->General) (11 May , 2011) [permalink]
    Some color manipulations are easier in HSL than RGB.
    // Based on Foley and van Dam algorithm.
    void ConvertRGBToHSL (const CGFloat *rgbComponents, CGFloat *hslComponents) {
        CGFloat red = rgbComponents[0];
        CGFloat green = rgbComponents[1];
        CGFloat blue = rgbComponents[2];
    
        CGFloat maxColor = MAX (red, MAX (green, blue));
        CGFloat minColor = MIN (red, MIN (green, blue));
        CGFloat deltaColor = maxColor - minColor;
    
        CGFloat hue, saturation;
        CGFloat lightness =  (maxColor + minColor) / 2.0;
    
        // All the same means a gray color.
        if (maxColor == minColor) {
            saturation = 0.0;
            hue = 0.0;  // officially undefined with gray, but go ahead and zero out.
    
        } else {
            if (lightness < 0.5) saturation = deltaColor / (maxColor + minColor);
            else                 saturation = deltaColor / (2.0 - deltaColor);
    
            if (red == maxColor)        hue = (green - blue) / deltaColor;
            else if (green == maxColor) hue = 2.0 + (blue - red) / deltaColor;
            else                        hue = 4.0 + (red - green) / deltaColor;
    
            // H will be in the range of 0..6, convert to degrees.
            hue *= 60.0;
    
            // Convert to positive angle.
            if (hue < 0) hue += 360.0;
        }
    
        // Clamp to legal values.
        hslComponents[0] = MAX (0.0, MIN (360.0, hue));
        hslComponents[1] = MAX (0.0, MIN (1.0, saturation));
        hslComponents[2] = MAX (0.0, MIN (1.0, lightness));
    
    } // ConvertRGBToHSL

  • Drawing a gradient (Graphics->General) (11 May , 2011) [permalink]
    - (void) drawGradientInRect: (CGRect) rect
                     colorSpace: (CGColorSpaceRef) colorSpcae
                        context: (CGContextRef) context {
        CGFloat startComponents[4] = { 254.0 / 255.0, 254.0 / 255.0, 254.0 / 255.0, 1.0 };
        CGFloat endComponents[4] = { 206.0 / 255.0, 206.0 / 255.0, 206.0 / 255.0, 1.0 };
        CGColorRef startColor = CGColorCreate (colorSpace, startComponents);
        CGColorRef endColor = CGColorCreate (colorSpace, endComponents);
    
        NSArray *array = [NSArray arrayWithObjects: (id)startColor, (id)endColor, nil];
    
        CGGradientRef gradient = CGGradientCreateWithColors (colorSpace,
                                                             (CFArrayRef)array, NULL);
        CGPoint endPoint = rect.origin;
        endPoint.y += rect.size.height;
    
        // Don't let the gradient bleed all over everything
        CGContextSaveGState (context); {
            CGContextClipToRect (context, rect);
            CGContextDrawLinearGradient (context, gradient, rect.origin, endPoint, 0);
        } CGContextRestoreGState (context);
    
        CGGradientRelease (gradient);
        CGColorRelease (startColor);
        CGColorRelease (endColor);
    
    } // drawGradientInRect
    

  • Counting number of words in a string (NSString->General) (05 May , 2011) [permalink]
    - (NSUInteger) countWords: (NSString *) string {
        NSScanner *scanner = [NSScanner scannerWithString: string];
        NSCharacterSet *whiteSpace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    
        NSUInteger count = 0;
        while ([scanner scanUpToCharactersFromSet: whiteSpace  intoString: nil]) {
            count++;
        }
    
        return count;
    
    } // countWords
    

  • Filtering an array (NSArray->General) (17 March , 2011) [permalink]
    You can use NSPredicate and -filteredArrayUsingPredicate: to selectively remove stuff from an array.
        NSPredicate *hasZone = [NSPredicate predicateWithBlock:
                                                ^BOOL (id obj, NSDictionary *bindings) {
                GRProfileCueTime *cueTime = obj;
                return cueTime.cue.targetHeartZone != kZoneNone;
            }];
        NSArray *justZones = [cues filteredArrayUsingPredicate: hasZone];
    
    This removes all of the elements of the array that do not have a target heart zone.

    If this kind of stuff is useful for you, you might want to check out Mike Ash's collection utilities.

  • Breaking on <Error>: doClip: empty path. (Graphics->Debugging) (15 March , 2011) [permalink]
    Sometimes you get the message <Error>: doClip: empty path. written to your console, with no obvious place to put a breakpoint. To find out where you're doing something wrong, put a breakpoint on CGPostError.

  • Changing title of Back Button (UIViewController->General) (03 February , 2011) [permalink]
    Sometimes the default title of the UIViewController "Back" button isn't quite right. To change it to something else, do this:
        UIBarButtonItem *backButton =
            [[UIBarButtonItem alloc] initWithTitle: @"Back"
                                     style: UIBarButtonItemStyleBordered
                                     target: nil
                                     action: nil];
        self.navigationItem.backBarButtonItem = backButton;
        [backButton release];
    
    The catch is you need to do it in the parent controller before pushing the subcontroller. You can stick this into the -init and change it once

  • Drawing a string centered in a rectangle (Graphics->General) (27 December , 2010) [permalink]
    - (void) drawText: (NSString *) text
       centeredInRect: (CGRect) rect
                 font: (UIFont *) font {
        CGSize textSize = [text sizeWithFont: font
                                constrainedToSize: rect.size
                                lineBreakMode: UILineBreakModeWordWrap];
    
        // Center text rect inside of |rect|.
        CGRect textRect = CGRectMake (CGRectGetMidX(rect) - textSize.width / 2.0,
                                      CGRectGetMidY(rect) - textSize.height / 2.0,
                                      textSize.width, textSize.height);
    
        [text drawInRect: textRect
              withFont: font
              lineBreakMode: UILineBreakModeWordWrap
              alignment: UITextAlignmentCenter];
    
    } // drawText
    
    

  • Converting touch coordinate to the view (UIView->General) (22 December , 2010) [permalink]
    - (void) touchesEnded: (NSSet *) touches  withEvent: (UIEvent *) event {
        UITouch *touch = [touches anyObject];
        CGPoint point = [touch locationInView: self];
        if (CGRectContainsPoint(self.bounds, point)) {
            NSLog (@"YAY!");
        }
    
    } // touchesEnded
    

  • Rounded rect path (Graphics->General) (20 December , 2010) [permalink]
    Returned path is refcounted, so you'll need to CFRelease when done.
    - (CGPathRef) newPathForRoundRect: (CGRect) rect
                            radius: (CGFloat) radius
                       strokeWidth: (CGFloat) strokeWidth {
    
        // Fit the stroked path inside the rectangle.
        rect.size.height -= strokeWidth;
        rect.size.width -= strokeWidth;
        rect.origin.x += strokeWidth / 2.0;
        rect.origin.y += strokeWidth / 2.0;
    
        CGMutablePathRef path = CGPathCreateMutable();
    
        // The inner rect size gives us X/Y/W/H values for the parts of the rect
        // that aren't on the curve.
        CGRect innerRect = CGRectInset(rect, radius, radius);
    
        CGFloat insideRight = innerRect.origin.x + innerRect.size.width;
        CGFloat outsideRight = rect.origin.x + rect.size.width;
        CGFloat insideBottom = innerRect.origin.y + innerRect.size.height;
        CGFloat outsideBottom = rect.origin.y + rect.size.height;
    
        CGFloat insideTop = innerRect.origin.y;
        CGFloat outsideTop = rect.origin.y;
        CGFloat outsideLeft = rect.origin.x;
    
        CGPathMoveToPoint (path, NULL, innerRect.origin.x, outsideTop);
    
        CGPathAddLineToPoint (path, NULL, insideRight, outsideTop);
        CGPathAddArcToPoint (path, NULL, outsideRight, outsideTop,
                             outsideRight, insideTop, radius);
    
        CGPathAddLineToPoint (path, NULL, outsideRight, insideBottom);
        CGPathAddArcToPoint (path, NULL,  outsideRight, outsideBottom,
                             insideRight, outsideBottom, radius);
    
        CGPathAddLineToPoint (path, NULL, innerRect.origin.x, outsideBottom);
        CGPathAddArcToPoint (path, NULL,  outsideLeft, outsideBottom,
                             outsideLeft, insideBottom, radius);
    
        CGPathAddLineToPoint (path, NULL, outsideLeft, insideTop);
        CGPathAddArcToPoint (path, NULL,  outsideLeft, outsideTop,
                             innerRect.origin.x, outsideTop, radius);
    
        CGPathCloseSubpath (path);
    
        return path;
    
    } // newPathForRoundRect
    
    If you're not in CGLand (or not needing the same code to work on the desktop and device), there's also UIBezierPath's -bezierPathWithRoundedRect:cornerRadius: (for all corners), and -bezierPathWithRoundedRect:byRoundingCorners:cornerRadii: (for some arbitrary subset of corners), and NSBezierPath's -bezierPathWithRoundedRect:xRadius:yRadius:. Muchos Thankos to Paul Collins for the reminder.

  • Using a stretchable UIImage (Graphics->General) (30 November , 2010) [permalink]
    Make an image somewhere (like in your -init):
            _timeIndicatorImage = [[[UIImage imageNamed: @"ride-profile-time-indicator"]
                                      stretchableImageWithLeftCapWidth: 0.0
                                      topCapHeight: 1.0] retain];
    
    Then draw it. In this case it's a vertical indicator.
    - (void) drawTimeIndicatorInRect: (CGRect) rect {
        CGFloat timeFraction = _time / _totalDuration;
    
        CGFloat x = [self horizontalPositionForTimeFraction: timeFraction];
    
        CGRect indicatorRect = CGRectMake (x, 0, 3.0, rect.size.height);
        [_timeIndicatorImage drawInRect: indicatorRect];
    
    } // drawTimeIndicatorInRect
    
    

  • Laying out tableview cell when entering / exiting edit mode (UITableView->General) (23 November , 2010) [permalink]
    Entering and exiting UITableView edit mode has a cool animation. If you've got a custom subclass, your goodies don't move unless you override layoutSubviews in your UITableViewCell subclass. Any view position changes will automatically be animated.
    - (void) layoutSubviews {
    
        // skootch stuff over
        if (self.editing && !self.showingDeleteConfirmation) {
    #define MARGIN 40.0
            CGRect frame = CGRectMake (MARGIN + 4.0, 4.0, 70.0, 46.0);
            _profileView.frame = frame;
    
            frame = CGRectMake (MARGIN + 80.0, 0, 240.0 - MARGIN, 55.0);
            _titleLabel.frame = frame;
    
        // layout normally
        } else {
            CGRect frame = CGRectMake (4.0, 4.0, 70.0, 46.0);
            _profileView.frame = frame;
    
            frame = CGRectMake (80.0, 0, 240.0, 55.0);
            _titleLabel.frame = frame;
        }
    
        [super layoutSubviews];
    } // layoutSubviews
    
    The showingDeleteConfirmation test is so you don't move things around if the user does the "swipe-right to show delete button" thing.

  • Open an URL in iphone safari (NSURL->General) (22 November , 2010) [permalink]
        NSURL *url = [NSURL URLWithString: @"http://cuteoverload.com/2006/09/12/xtreme_gluttony/"];
        [[UIApplication sharedApplication] openURL: url];
    

  • Getting selected row from UITableView (UITableView->General) (18 November , 2010) [permalink]
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        if (indexPath != nil) [self doStuff];
    

  • Drawing outlined / filled text (Graphics->General) (12 November , 2010) [permalink]
    I wanted to draw text like this:

    - (void) drawRect: (CGRect) rect {
        NSString *string = @"132";
    
        CGContextRef ctx = UIGraphicsGetCurrentContext ();
    
        CGContextTranslateCTM (ctx, 0.0, self.bounds.size.height);
        CGContextScaleCTM (ctx, 1.0, -1.0);
    
        CGContextSelectFont (ctx, "Helvetica-Bold", 48.0, kCGEncodingMacRoman);
        CGContextSetTextDrawingMode (ctx, kCGTextFillStroke);
    
        // Draw a background to see the text on.
        CGContextSetFillColorWithColor (ctx, [[UIColor yellowColor] CGColor]);
        CGContextFillRect (ctx, self.bounds);
    
        CGContextSetFillColorWithColor (ctx, [[UIColor blackColor] CGColor]);
        CGContextSetStrokeColorWithColor (ctx, [[UIColor whiteColor] CGColor]);
    
        CGContextSetLineWidth (ctx, 2);
        CGContextSetShadow (ctx, CGSizeMake (3.0, 3.0), 2.5);
        CGContextShowTextAtPoint (ctx, 50, 50, [string UTF8String], string.length);
    
    } // drawRect
    
    (Thanks to Chris Liscio for handy pointers)

  • Getting the duration of an audio file (Audio->General) (28 October , 2010) [permalink]
    #import <AudioToolbox/AudioToolbox.h>
    ...
    - (NSTimeInterval) voiceCueLength {
        NSTimeInterval length = 0.0;
        NSURL *audioURL = [NSURL fileURLWithPath: self.pathToVoiceCue];
    
        OSStatus result = noErr;
    
        AudioFileID audioFile = NULL;
        result = AudioFileOpenURL ((CFURLRef)audioURL,
                                   kAudioFileReadPermission,
                                   0, // hint
                                   &audioFile);
        if (result != noErr) goto bailout;
    
        //Get file length
        NSTimeInterval seconds;
        UInt32 propertySize = sizeof (seconds);
        result = AudioFileGetProperty (audioFile,
                                       kAudioFilePropertyEstimatedDuration,
                                       &propertySize,
                                       &seconds);
        if (result != noErr) goto bailout;
    
        length = seconds;
    
      bailout:
        if (audioFile) AudioFileClose (audioFile);
        return length;
    } // voiceCueLength
    
    And Link with the AudioToolbox framework.

  • Creating a UUID (General->General) (15 October , 2010) [permalink]
    CFUUIDRef cfuuid = CFUUIDCreate (kCFAllocatorDefault);
    NSString *uuid = (NSString *)CFUUIDCreateString (kCFAllocatorDefault, cfuuid);
    CFRelease (cfuuid);
    Because a core foundation "Create" function is called, you're responsible for releasing uuid when you're done with it.

  • Changing UIButton title (UIButton->General) (15 October , 2010) [permalink]
    [_rejectButton setTitle: @"My Spoon is Too Big"  forState: UIControlStateNormal];
    

  • Displaying stuff on a monitor hooked up to the phone (UIView->General) (12 October , 2010) [permalink]
    BOOL haveSecondScreen = [UIScreen screens].count > 1;
    
    if (haveSecondScreen) {
        UIScreen *screen = [[UIScreen screens] objectAtIndex: 1];
    
        // Figure out the largest screen mode we can use.
        CGSize max = CGSizeMake (0.0, 0.0);
        UIScreenMode *maxScreenMode = nil;
        for (UIScreenMode *mode in [screen availableModes]) {
            if (mode.size.width * mode.size.height > max.width * max.height) {
                max = mode.size;
                maxScreenMode = mode;
            }
        }
        screen.currentMode = maxScreenMode;
    
        UIView *view = [[UIView alloc] initWithFrame: screen.bounds];
        view.backgroundColor = [UIColor greenColor];
    
        UIWindow *window = [[UIWindow alloc] init];
        window.screen = screen;
        [window addSubview: view];
        window.hidden = NO;
    
        [view release];
        // Stash |window| into an ivar or something.
    }
    This doesn't deal with stuff like aspect ratios, etc.

  • Discriminating single and double tap gesture (UIView->General) (04 October , 2010) [permalink]
    You want a single tap to do something, and a double tap to do something else. You don't want the single tap to fire unless it's fer sher not a double-tap. (assuming you can live for the timeout before your single tap gesture happens). You can make the single-tap recognizer wait until the double-tap one fails:
        UITapGestureRecognizer *singleTap =
            [[UITapGestureRecognizer alloc] initWithTarget: self
                                            action: @selector(startStop:)];
        singleTap.numberOfTapsRequired = 1;
        singleTap.numberOfTouchesRequired = 1;
        [self addGestureRecognizer: singleTap];
    
        UITapGestureRecognizer *doubleTap =
            [[UITapGestureRecognizer alloc] initWithTarget: self
                                            action: @selector(resetTimer:)];
        doubleTap.numberOfTapsRequired = 2;
        doubleTap.numberOfTouchesRequired = 1;
        [self addGestureRecognizer: doubleTap];
    
        [singleTap requireGestureRecognizerToFail: doubleTap];
    
        [singleTap release];
        [doubleTap release];
    
    

  • Adding a plus button to a navigation bar (UINavigationController->General) (28 September, 2010) [permalink]
        UIBarButtonItem *addButton  =
            [[UIBarButtonItem alloc]
                initWithBarButtonSystemItem: UIBarButtonSystemItemAdd
                target: self
                action: @selector(addNewSegment)];
        self.navigationItem.rightBarButtonItem = addButton;
        [addButton release];
    

  • Setting a cell's background color (UITableView->General) (27 September, 2010) [permalink]
    cell.textLabel.backgroundColor = [UIColor redColor];
    cell.contentView.backgroundColor = [UIColor redColor];

  • Clipping cell image drawing to rounded corners of grouped tables (UITableView->Hacks) (24 September, 2010) [permalink]
    If you have a grouped UITableView, the top and bottom cells of each group are rounded. If you have an image in the cell, it will obliterate the left-hand corners. There's a number of ways to properly fix this : pre-clip your images with some transparency at the corners. Set up a clipping path before drawing the cell, or playing with the image view's cell layer.

    Or you can hack it by setting the cell's indent to 1. That scoots the whole cell contents over by 10 pixels, letting you miss the rounded corners. Really handy if you're prototyping, want something to look non-horrible, but don't want to go the full-blown correct solution.

  • Setting a cell's image (UITableView->General) (20 September, 2010) [permalink]
       UIImage *image = [_assets iconAtIndex: indexPath.row];
        if (image) cell.imageView.image = image;

  • Performing one-time initialization (Blocks->General) (11 September, 2010) [permalink]
    You can use libdispatch / Grand Central Dispatch, to execute a block that must run once, and only once, no matter how many threads are knocking at its door.
    + (void) initialize {
        static dispatch_once_t init_predicate;
    
        dispatch_once (&init_predicate, ^{ 
                CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB ();
    
                for (int i = 0; i < 7; i++) {
                    CGFloat components[] = { rawZoneColors[i]._red,
                                             rawZoneColors[i]._green,
                                             rawZoneColors[i]._blue,
                                             rawZoneColors[i]._alpha };
                    zoneColors[i] = CGColorCreate (rgbSpace, components);
                }
            });
    
    } // initialize
    

  • Toggling an index in an NSMutableIndexSet (General->General) (06 September, 2010) [permalink]
    NSUInteger index = indexPath.row; if ([_selection containsIndex: index]) [_selection removeIndex: index]; else [_selection addIndex: index];

  • Block Typedef (Blocks->General) (02 September, 2010) [permalink]
    I can never remember the syntax for function pointer typedefs, and therefore can never remember the syntax for block typedefs:
    typedef CGRect (^GroovyBlock)(NSInteger spoon, NSString *waffle);
    Creates a typedef called GroovyBlock that returns a CGRect and takes an integer and a string.

  • Adding gesture recognizers (UIView->General) (26 August , 2010) [permalink]
    Gesture recognizers are cool. Here is how you can add them to a UIView, say at init or view loading time:
        UITapGestureRecognizer *tap =
            [[UITapGestureRecognizer alloc] initWithTarget: self
                                            action: @selector(twoByThreeTap:)];
        tap.numberOfTapsRequired = 2;
        tap.numberOfTouchesRequired = 3;
        [self addGestureRecognizer: tap];
        [tap release];
    If you're not getting taps, perhaps you're using a default UIImageView, you'll probably need to turn on interaction and multitouch, either in IB or in code:
        // So we can get the taps.
        self.userInteractionEnabled = YES;
        self.multipleTouchEnabled = YES;

  • Using an NSOpenPanel (General->General) (23 August , 2010) [permalink]
    Using an NSOpenPanel with blocks:
    - (IBAction) openEarthinizerDoc: (id) sender {
        NSOpenPanel *panel = [NSOpenPanel openPanel];
    
        [panel beginSheetModalForWindow: self.window
               completionHandler: ^(NSInteger result) {
                if (result == NSFileHandlingPanelOKButton) {
                    NSURL *url = [[panel URLs] objectAtIndex: 0];
                    [self openURL: url];
                }
            }];
    
    } // openEarthinizerDoc
    

  • Processing every line in a string (NSString->NSArray) (23 August , 2010) [permalink]
    Say you got a string that's composed of one interesting data item per line, like /usr/share/dict/words or from a script, and you want to process them. In this case turning a bunch of strings into floats:
        NSMutableArray *altitudes = [NSMutableArray array];
        NSString *altitudeString = [self altitudeStringFromGoogle: coords];
    
        [altitudeString enumerateLinesUsingBlock: ^(NSString *line, BOOL *stop) {
                float value = [line floatValue];
                [altitudes addObject: [NSNumber numberWithFloat: value]];
            }];

  • Where to put files for the system-wide web server (Random->Random) (19 August , 2010) [permalink]
    When you turn on web sharing, the OS starts up an Apache for you, returning a default "It works!" page when you visit it. You can put your own content in the webserver by dropping files into:
    /Library/WebServer/Documents

  • Turning off screen dimming / locking (Hacks->General) (27 July , 2010) [permalink]
    iDevices after a period of no user interaction will dim the screen and eventually lock it. If you have a hands-free app, or one that's primarily passive, this is unuseful behavior.

    The UIApplication itemTimerDisabled controls whether the screen should dim. Disable it by enabling it:

    [[UIApplication sharedApplication] setIdleTimerDisabled: YES];
    or equivalently
    [UIApplication sharedApplication].idleTimerDisabled = YES;

    Unfortunately, this is not a reliable operation. Sometimes twiddling a UI control or playing music will let the screen dim and lock up. What I ended up doing is toggling the value in a timer:

    [[UIApplication sharedApplication] setIdleTimerDisabled: NO];
    [[UIApplication sharedApplication] setIdleTimerDisabled: YES];

  • Creating a new index path (UITableView->General) (23 July , 2010) [permalink]
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow: row
                                              inSection: 0];
    

  • Invalidating a single row (UITableView->General) (23 July , 2010) [permalink]
    Sometimes you want to update a single row of a tableview as new information comes in. Such as loading something in the background and you want to update a percentage being shown in the cell. You could -reloadData, but don't. That's an awfully big hammer. Instead just reload a row
           NSIndexPath *indexPath = [NSIndexPath indexPathForRow: row
                                                  inSection: 0];
            NSArray *array = [NSArray arrayWithObject: indexPath];
            [_playlistTableView reloadRowsAtIndexPaths: array
                                withRowAnimation: UITableViewRowAnimationNone];

  • Getting UILabel to word-wrap in IB. (UILabel->General) (22 July , 2010) [permalink]
    You can get a UILabel to word-wrap its contents in IB. The trick is to set "Line Breaks" to "Word Wrap" and "Lines" to zero.

  • Removing yourself from notifications (Notifications->General) (21 July , 2010) [permalink]
    Don't forget to unregister yourself from the notification center in your -dealloc:
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        [center removeObserver: self];
    

  • Changing UITableViewCell label text color (UITableView->General) (21 July , 2010) [permalink]
        if (someProperty) cell.textLabel.textColor = [UIColor grayColor];
        else cell.textLabel.textColor = [UIColor blackColor];
    

  • Tableview subtitle cell (UITableView->General) (21 July , 2010) [permalink]
    The subtitle cell has a large label and a smaller gray-text sublabel.

    Make the cell with UITableViewCellStyleSubtitle:

            cell = [[[UITableViewCell alloc]
                        initWithStyle: UITableViewCellStyleSubtitle
                        reuseIdentifier: @"UITableViewCell"] autorelease];
    
    and set the label values:
        cell.textLabel.text = @"somewhere";
        cell.detailTextLabel.text = @"over the rainbow";
    

  • Adding an index to a tableview (UITableView->General) (19 July , 2010) [permalink]
    Some tableviews have the short-cut list thingie on the side, which apple calls the index. The index is section-based - each entry in the index corresponds to a section in your data. So if you have a pretty flat list (just an NSArray, for instance), you'll either need to map section-> index, or split up your data so it's physically organized in section/row.

    And then override these. In this case, I split up an array into an array of arrays, each sub-array being the contents of a section that corresponds to a string to display in the index. _tableIndex is an array of strings for display of the index.

    - (NSArray *) sectionIndexTitlesForTableView: (UITableView *) tableView {
        return _tableIndex;
    } // sectionIndexTitles
    
    
    - (NSInteger) tableView: (UITableView *) tableView
    sectionForSectionIndexTitle: (NSString *) title
                    atIndex: (NSInteger) index {
        return index;
    } // sectionForSectionIndexTitle

  • Scrolling to a row in a UITableView (UITableView->General) (19 July , 2010) [permalink]
        NSIndexPath *someRow = [NSIndexPath indexPathForRow: random() % blah.count
    					inSection: 0];
        [self.cuesTableView scrollToRowAtIndexPath: someRow
             atScrollPosition: UITableViewScrollPositionBottom
             animated: YES];
    You can also scroll to PositionTop and PositionMiddle. If you crash, make sure you've done a -reloadData on the table view prior to trying to scroll.

  • Turning off UITableView scrolling (UITableView->General) (19 July , 2010) [permalink]
    _tableView.scrollEnabled = NO;

  • Making object subclasses appear in NSSets (NSSet->General) (19 July , 2010) [permalink]
    Have an object you've put into an NSSet, and things don't seem to be working? Make sure you implement -isEqual: and -hash
    - (BOOL) isEqual: (id) object;
    - (NSUInteger) hash;

  • Controlling UITableView row rearranging (UITableView->General) (18 July , 2010) [permalink]
    Say that you want to let the user rearrange tableview rows except for the first and the last, which can't move. First, inhibit the drawing of the little rearrange indicator on the first and last rows:
    - (BOOL) tableView: (UITableView *) tableView
      canMoveRowAtIndexPath: (NSIndexPath *) indexPath {
    
        if (indexPath.row == 0) return NO;
        else if (indexPath.row == _cues.count - 1) return NO;
        else return YES;
    
    } // canMoveRowAtIndexPath
    And then prevent rows from being dragged to the first and last position:
    - (NSIndexPath *) tableView: (UITableView *) tableView
    targetIndexPathForMoveFromRowAtIndexPath: (NSIndexPath *) source
            toProposedIndexPath: (NSIndexPath *) destination {
    
        if (destination.row > 0 && destination.row < _cues.count - 1) {
            // No violence necessary.
            return destination;
        }
    
        NSIndexPath *indexPath = nil;
    
        // If your table can have <= 2 items, you might want to robusticize the index math.
        if (destination.row == 0) {
            indexPath = [NSIndexPath indexPathForRow: 1  inSection: 0];
        } else {
            indexPath = [NSIndexPath indexPathForRow: _cues.count - 2
                                     inSection: 0];
        }
    
        return indexPath;
    
    } // targetIndexPathForMoveFromRowAtIndexPathPleaseOHaiThanksForMovingKthxBai

  • Handling UITableView row deletion (UITableView->General) (18 July , 2010) [permalink]
    - (void) tableView: (UITableView *) tableView
    commitEditingStyle: (UITableViewCellEditingStyle) editingStyle
     forRowAtIndexPath: (NSIndexPath *) indexPath {
        if (editingStyle == UITableViewCellEditingStyleDelete) {
            [_cues removeObjectAtIndex: indexPath.row];  // manipulate your data structure.
            [tableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: indexPath]
                       withRowAnimation: UITableViewRowAnimationFade];
            [self updateUI];  // Do whatever other UI updating you need to do.
        }
    } // commitEditingStyle
    

  • Putting UITableView into editing mode (UITableView->General) (18 July , 2010) [permalink]
    UITableView editing mode lets you delete / rearrange / insert rows. Turn it on via
        [self.cuesTableView setEditing: YES  animated: YES];
    

  • Rearranging in UITableView (UITableView->General) (18 July , 2010) [permalink]
    Implementing this method in your UITableView datasource will make the table draw the little rearrange marker on each row.
    - (void) tableView: (UITableView *) tableView
    moveRowAtIndexPath: (NSIndexPath *) from
           toIndexPath: (NSIndexPath *) to {
        // How to rearrange stuff if you're backed by an NSMutableArray:
        GRCue *cue = [_cues objectAtIndex: from.row];
        [cue retain];  // Let it survive being removed from the array.
        [_cues removeObjectAtIndex: from.row];
        [_cues insertObject: cue  atIndex: to.row];
        [cue release];
    
    } // moveRowAtIndexPath
    

  • Are we compiling for the device, simulator, or other? (Building->General) (15 July , 2010) [permalink]
    // Are we compiling for the device, simulator, or desktop?
    #if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
    #define GR_TARGET_SIMULATOR 1
    
    #elif TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
    #define GR_TARGET_DEVICE 1
    
    #else
    #define GR_TARGET_DESKTOP 1
    
    #endif
    Then I use the GR_TARGET symbols for #if'ing in platform-specific chunklets of code.

  • Selecting a row in a UIPickerView (UIPickerView->General) (14 July , 2010) [permalink]
        [_durationPicker selectRow: row
                         inComponent: 0
                         animated: NO];
    

  • UIPickerView delegate and datasource methods (UIPickerView->General) (14 July , 2010) [permalink]
    - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
    
    - (NSInteger) pickerView: (UIPickerView *) picker
     numberOfRowsInComponent: (NSInteger) component
    
    - (NSString *) pickerView: (UIPickerView *) picker
                  titleForRow: (NSInteger) row
                 forComponent: (NSInteger) component
    
    - (void) pickerView: (UIPickerView *) picker
           didSelectRow: (NSInteger) row
            inComponent: (NSInteger) component
    

  • Popping the current view controller (UINavigationController->General) (13 July , 2010) [permalink]
    Say the user selected a row in a tableview, and now we're done with this view controller:
    - (void)tableView: (UITableView *) tableView
        didSelectRowAtIndexPath: (NSIndexPath *) indexPath {
    
        // might want someone to know what the user picked.
        [_delegate kindChooser: self
                   choseWorkoutType: mapRowToWorkoutType(indexPath.row)];
    
        // pop ourselves off the stack.
        [self.navigationController popViewControllerAnimated: YES];
    
    } // didSelectRowAtIndexPath
    

  • Finding the row from a tableview cell button (UITableView->General) (13 July , 2010) [permalink]
    You can add buttons to a UITableViewCell. The fun part is figuring out what row that button lives on. Assuming that the button is added right to the cell, you can look at the button's superview to get the cell, and then ask the tableview for the cell's section and row.
    - (IBAction) elaborateType: (id) sender {
        if (![sender isKindOfClass: [UIButton class]]) return;  // be paranoid
    
        UITableViewCell *cell = (UITableViewCell *)[sender superview];
        if (![cell isKindOfClass: [UITableViewCell class]]) return;  // be paranoid
    
        NSIndexPath *indexPath = [self.kindPickerTableView indexPathForCell: cell];
    
        // do something with indexPath.row and/or indexPath.section.
    
    } // elaborateType

  • Pushing a new view controller onto the stack. (UINavigationController->General) (11 July , 2010) [permalink]
    Moving to another view controller from the current one.
        GRChooseRideKindViewController *chooseKind =
            [[GRChooseRideKindViewController alloc] init];
    
        [self.navigationController pushViewController: chooseKind
             animated: YES];
    
        [chooseKind release];

  • Adding an arrow thingie or checkbox to tableview cells (UITableView->General) (11 July , 2010) [permalink]
    If you have the cell, you can set the accessoryType directly:
    UITableViewCell *cell = ...;
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    The delegate method (accessoryTypeForRowWithIndexPath) has been deprecated, so don't use that.

    Use UITableViewCellAccessoryCheckmark for a checkmark.

    Use UITableViewCellAccessoryNone to remove the checkmark.

  • Add a cancel button to a navigation bar. (UINavigationController->General) (09 July , 2010) [permalink]
    In your -viewDidLoad :
        UIBarButtonItem *cancelButton =
    	[[UIBarButtonItem alloc] initWithTitle: @"Cancel"
                                     style: UIBarButtonItemStylePlain
                                     target: self
                                     action: @selector(cancel:)];
        self.navigationItem.rightBarButtonItem = cancelButton;
        [cancelButton release];

  • Hide the navigation bar's "Back" button. (UINavigationController->General) (09 July , 2010) [permalink]
        self.navigationItem.hidesBackButton = YES;

  • Hiding the navigation bar (UINavigationController->General) (09 July , 2010) [permalink]
    Say you had a main screen that doesn't need to show the navigation bar. When you "Back" from another view controller your delegate will get called. You can decide then whether to turn off the nav bar.
    - (void) navigationController: (UINavigationController *) navigationController
           willShowViewController: (UIViewController *) viewController
                         animated: (BOOL) animated {
        if (viewController == _menuController) {
            [_navigationController setNavigationBarHidden: YES
                                   animated: YES];
        }
    } // willShowViewController
    

  • Adding blah@2x.png files to subversion (Subversion->Hacks) (06 July , 2010) [permalink]
    I personally dislike Apple's "@2x" nomenclature for high-def images for iDevices. But we're stuck with it. The embedded at-sign confuses subversion unless you append the file name with an at-sign:
    % svn add bunnies@2x.png
    svn: warning: 'bunnies' not found
    % svn add bunnies@2x.png@
    A         bunnies@2x.png
    
    (thanks to Gus Mueller, Mike Ash, and Guy English)

  • Deserializing with TouchJSON (JSON->General) (05 July , 2010) [permalink]
        #import "CJSONDeserializer.h"
    
        NSData *jsonData = [NSData dataWithContentsOfFile: path]; // or from network, or whatever
        NSError *error;
        NSArray *playlists =
            [[CJSONDeserializer deserializer] deserializeAsArray: jsonData
                                              error: &error];
    

  • Serializing with TouchJSON (JSON->General) (05 July , 2010) [permalink]
        #import "CJSONSerializer.h"
    
        NSArray *allSongs = [self allSongs];
        NSString *jsonString = [[CJSONSerializer serializer] serializeObject: allSongs];
        NSData *data = [jsonString dataUsingEncoding: NSUTF8StringEncoding];
        // write |data| to a file, send over the network, etc
    

  • Draw a string in bold (NSString->Graphics) (01 July , 2010) [permalink]
    - (void) drawLabel: (NSString *) label
               atPoint: (NSPoint) point
                  bold: (BOOL) bold {
        NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
        NSFont *currentFont = [NSFont userFontOfSize: 14.0];
    
        if (bold) {
    	NSFontManager *fm = [NSFontManager sharedFontManager];
    	NSFont *boldFont = [fm convertFont: currentFont
                                   toHaveTrait: NSBoldFontMask];
    	[attributes setObject: boldFont
                        forKey: NSFontAttributeName];
        } else {
    	[attributes setObject: currentFont
                        forKey: NSFontAttributeName];
        }
    
        [label drawAtPoint: point  withAttributes: attributes];;
    
    } // drawLabel
    

  • Quicktime X Player A/V controls (General->General) (24 June , 2010) [permalink]
    When watching pre-recorded sessions from technical conferences, I like to speed them up. Usually I can speed up things to 1.5x to 1.8x speed and still understand what's going on. I was able to speed Matt Gemmell up to 2.5x and could still understand him. Amazing. Quicktime 7 had nice A/V controls to speed up the video. You can download Quicktime 7 and use its player.

    Quicktime X's player doesn't have an A/V controls window, but you can option-click the fast-forward button to increase the speed by 0.1x. Keep clicking to go faster. Unfortunately you can't pause when sped up, so if you pause, you have to re-click to your desired speedup.

  • Setting environment variables (lldb->General) (23 June , 2010) [permalink]
    (lldb) set env-vars OOP=ack BORK=greeble

  • Hexdump in gdb (gdb->General) (16 June , 2010) [permalink]
    (gdb) x /80xb attrBuffer
    will give you something like
    0x7fff5fbfeeb0: 0x14    0x00    0x00    0x00    0xdb    0x0b    0x19    0x4c
    0x7fff5fbfeeb8: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
    0x7fff5fbfeec0: 0x00    0x00    0x00    0x00    0xec    0xc8    0x62    0xe5
    0x7fff5fbfeec8: 0xc7    0x48    0x18    0xd2    0xe7    0x9e    0x88    0xd8
    0x7fff5fbfeed0: 0xd9    0x60    0x9f    0x61    0xea    0x37    0x3b    0x0c
    0x7fff5fbfeed8: 0x87    0x1b    0x4e    0x7e    0x6a    0x26    0x98    0x62
    0x7fff5fbfeee0: 0x6d    0x01    0xed    0xed    0x17    0x6d    0xae    0x05
    0x7fff5fbfeee8: 0xe7    0x22    0xd0    0x96    0x33    0x34    0x16    0x1a
    0x7fff5fbfeef0: 0x17    0xa7    0x87    0xb2    0x76    0x7b    0x29    0x0b
    0x7fff5fbfeef8: 0xea    0x51    0x4c    0x45    0x4f    0x45    0x65    0x88

  • Creating scripting bridge header file for an app (AppleScript->General) (26 May , 2010) [permalink]
    % sdef /Applications/iTunes.app | sdp -fh --basename iTunes
    
    Makes iTunes.h

  • Rotating a layer by 90 degrees (Core Animation->General) (20 May , 2010) [permalink]
    To rotate a 'flat' layer, gotta convert degrees to radians, and then rotate around a vector along the z axis.
    hooverLayer.transform = CATransform3DRotate(CATransform3DIdentity,
                                                90.0 * M_PI / 180.0,
                                                0.0f, 0.0f, 1.0f);
    

  • Responding to table taps (UITableView->General) (10 May , 2010) [permalink]
    Set yourself up as the UITableView delegate first.
    - (void)tableView: (UITableView *) tableView
        didSelectRowAtIndexPath: (NSIndexPath *) indexPath {
        // Do something logical with indexPath.row, etc.
    } // didSelectRowAtIndexPath
    

  • Selecting a row in a UITableView (UITableView->General) (10 May , 2010) [permalink]
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow: index
                                              inSection: 0];
        [self.tableView reloadData];  // necessary if selecting row in -viewDidLoad
    
        [self.tableView selectRowAtIndexPath: indexPath
                        animated: YES
                        scrollPosition: UITableViewScrollPositionNone];
    

  • Adding a target/action to a UIButton (UIButton->General) (09 May , 2010) [permalink]
        [playButton addTarget: self
                    action: @selector(play)
                    forControlEvents: UIControlEventTouchUpInside];
    

  • Table view data source foobage (UITableView->General) (07 May , 2010) [permalink]
    // Optional
    - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView {
        return 1;
    } // numberOfSectionsInTableView
    
    
    - (NSInteger) tableView: (UITableView *) tableView
      numberOfRowsInSection: (NSInteger) section {
        return dataArray.count;
    } // numberOfRowsInSection
    
    
    - (UITableViewCell *) tableView: (UITableView *) tableView
              cellForRowAtIndexPath: (NSIndexPath *) indexPath {
    
        UITableViewCell *cell =
            [tableView dequeueReusableCellWithIdentifier: @"BlahTableViewCell"];
    
        if (!cell) {
            cell = [[UITableViewCell alloc]
                       initWithStyle: UITableViewCellStyleDefault
                       reuseIdentifier: @"BlahTableViewCell"];
            [cell autorelease];
        }
    
        cell.textLabel.text = [dataArray objectAtIndex: indexPath.row];
    
        return cell;
    
    } // cellForRowAtIndexPath
    

  • Making BNR-Style View Controller (UIViewController->General) (04 May , 2010) [permalink]
    One of the things I like about the Big Nerd Ranch iPhone book is how they put the name of the nib file in a ViewController's implementation, rather than making all users of the ViewController know the nib file name. Here's how they do it:
    @implementation BlahViewController
    
    - (id) init {
        if ((self = [super initWithNibName: @"BlahViewController"
                           bundle: nil])) {
            // other initialization
        }
        return self;
    } // init
    
    
    - (id) initWithNibName: (NSString *) nibNameOrNil
                    bundle: (NSBundle *) nibBundleOrNil {
        return [self init];
    } // initWithNibName
    

  • Displaying a UIAlert (UIAlert->General) (04 May , 2010) [permalink]
        UIAlertView *alert =
            [[UIAlertView alloc] initWithTitle: @"Some Title"
                                 message: @"You look very nice today."
                                 delegate: self
                                 cancelButtonTitle: @"OK"
                                 otherButtonTitles: nil];
        [alert show];
        [alert release];
    
    If you want to know what got tapped, use a delegate method. The cancel button is index zero.
    - (void) alertView: (UIAlertView *) alertView
        clickedButtonAtIndex: (NSInteger) buttonIndex {
        NSLog(@"foobage! %d", buttonIndex);
    } // clickedButtonAtIndex
    

  • Binding an NSPopupButton (General->General) (29 December , 2009) [permalink]
    To bind an NSPopupButton:
    • Have an NSArray somewhere that you want to supply the popup
    • Make an NSArrayController in the nib file (say call it "greeble"), and binds its Value to some keypath (such as your AppDelegate.greebleArray ivar)
    • Bind the popup's Content to the array controller's arranged objects (greeble.arrangedObjects). These are the objects that are behind the popup.
    • Bind the popup's Content Values to a key path that includes a displayable string. Assuming the objets in the greebleArray array have a title property, you'd bind it to greeble.arrangedObjects.title
    • Bind the popup's Selected Object to something, such as an ivar of the type of object that's in the greebleArray. If said ivar is called selectedGreeble, you'd bind to AppDelegate's selectedGreeble.

  • Continuous Text Field (General->General) (29 December , 2009) [permalink]
    Courtesy of Jens Bauer. Sometimes you'd like a text field to notify on every text change.
    @interface FSContinousTextField : NSTextField
    @end
    
    @implementation FSContinousTextField
    
    - (void) textDidChange: (NSNotification *) aNotification {
    	[[self target] performSelector:[self action] withObject:self];
    }
    
    @end

  • Hiding TOC bar in xcode permanently (Xcode->General) (29 December , 2009) [permalink]
    Thanks to Jens Bauer who sent this my way. "When I option-double-click an object in my source-code, I got a surprise with newer Xcodes. There's a huge TOC bar in the left side, forcing me to have a large window, that overlaps my source-code, so I can't look at the documentation and type at the same time. Furthermore it makes the sentences very 'tall', which I can't get used to. So I dropped my coding, went for a hunt. I wanted to go and get rid of that annoying demon. I found it and cast it out (By hand!)"

    Here's how Jens cast out that demon. It's two different edits:

    To make the TOC section (left side bar) of the developer documentation default to be hidden, do as follows:

    Before you begin, make the two files and their parent-folders writable.

    In the file....

    /Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Resources/CSS/frameset_styles.css

    ...change the line...

    #bodyText { margin-left: 210px; }

    ...to read...

    #bodyText { /* margin-left: 210px; */ margin-left:10px; /* TOC-FIX */ }

    ...And in the file...

    /Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Resources/JavaScript/page.js

    ...add the following somewhere in initialize_page() function, for instance at the bottom, right before the closing brace...

    showHideTOC('hide'); // TOC-FIX

    ...now you have a much better view!!

    Note that you'll need to apply this patch when the docs get upgraded.

  • Converting xsd:date to NSDate (NSDate->General) (25 December , 2009) [permalink]
    xsd:date has a format that's a subset of the full ISO8601 format. Here's a quick way to convert an xsd:date to an NSDate. Based on a forum posting by Jens Alfke. For a full ISO 8601 parser, check out the one by Peter Hosey.

    Note that thiscode

    NSDate *xsdDateTimeToNSDate (NSString *dateTime) {
        static NSDateFormatter *xsdDateTimeFormatter;
        if (!xsdDateTimeFormatter) {
            xsdDateTimeFormatter = [[NSDateFormatter alloc] init];  // Keep around forever
            xsdDateTimeFormatter.timeStyle = NSDateFormatterFullStyle;
            xsdDateTimeFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:sszzz";
        }
    
        // Date formatters don't grok a single trailing Z, so make it "GMT".
        if ([dateTime hasSuffix: @"Z"]) {
            dateTime = [[dateTime substringToIndex: dateTime.length - 1]
                           stringByAppendingString: @"GMT"];
        }
    
        NSDate *date = [xsdDateTimeFormatter dateFromString: dateTime];
        if (!date) NSLog(@"could not parse date '%@'", dateTime);
    
        return (date);
    
    } // xsdDateTimeToNSDate
    

  • Ignore files (Mercurial->General) (25 December , 2009) [permalink]
    Tired of build directories or .DS_Store files showing up in hg status? Make a .hgignore at the top level of your repository. It supports glob and regex, and plain names.man hgignore for more details.

  • Supplying bitbucket username / password (Mercurial->General) (25 December , 2009) [permalink]
    BitBucket provides Mercurial hosting. It's kind of a pain to have to provide a username/password on every pull or push. So, just add something like this to your ~/.hgrc file and make sure the permissions on the file are such that nobody else can read it.
    [auth]
    bitbucket.prefix = bitbucket.org/markd2
    bitbucket.username = markd2
    bitbucket.password = B4dg3rzRuL3
    bitbucket.schemes = http https
    
    So now when you do a
    % hg push https://bitbucket.org/markd2/borkfit
    
    no need to authorize.

  • Trimming whitespace from ends of a string (NSString->General) (24 December , 2009) [permalink]
        NSString *ook = @"\n \t\t hello there \t\n  \n\n";
        NSString *trimmed =
            [ook stringByTrimmingCharactersInSet:
                     [NSCharacterSet whitespaceAndNewlineCharacterSet]];
    
        NSLog(@"trimmed: '%@'", trimmed);
    
    produces
    2009-12-24 18:24:42.431 trim[6799:903] trimmed: 'hello there'
    

  • Beware BOOL results from objc_msgSend (Objective-C->Random) (17 November , 2009) [permalink]
    Courtesy of David Philip Oster, from GTMNSEnumerator+Filter.m:
    // We must take care here, since Intel leaves junk in high bytes of return register
    // for predicates that return BOOL.
    // For details see: 
    // unibin chapter and verse (link currently broken courtesy of Apple)
    // and
    //comment at red-sweater.
    - (BOOL)filterObject:(id)obj returning:(id *)resultp {
      *resultp = obj;
      return ((BOOL (*)(id, SEL, id))objc_msgSend)(obj, operation_, object_);
    }
    
    The explicit cast to the expected return value gets rid of the junk.

  • Lie in wait for a launching process (gdb->General) (24 August , 2009) [permalink]
    Attaching to a running process is pretty nifty, handy for debugging daemons started by launchd. But you miss all the fun stuff that happens at program launch before you you can attach to it.

    The attach command's -waitfor option to make gdb lie in wait for a launching process:

    % gdb /some/app/blah
    (gdb) attach -waitfor blah
    
    Now when a blah process launches, gdb will stop it and attach to it.

  • Convert a preprocessor symbol to an NSString (General->General) (11 August , 2009) [permalink]
    #define CONVERT_SYMBOL_TO_NSSTRING_2(x) @#x
    #define CONVERT_SYMBOL_TO_NSSTRING(x) CONVERT_SYMBOL_TO_NSSTRING_2(x)
    
    NSString *version = CONVERT_SYMBOL_TO_NSSTRING (BUILD_NUMBER);
    
    (Thanks to TVL for helping me figure this one out)

  • Running a particular architecture (Tools->Hacks) (01 June , 2009) [permalink]
    otest is kind of annoying that it tries to run the 64 bit version of your unit tests, especially if you don't have any. Typically you'd get an error like
    2009-06-01 12:49:29.447 otest[70099:203] *** NSTask: Task create for path '/blah/blah/blah' failed: 8, "Exec format error". Terminating temporary process.
    You can force otest to run a particular architecture with the arch command:
    %  arch -arch i386 /Developer/Tools/otest build/Debug/Snoogle.octest
    

  • Creating a disk image from the command line (Unix->General) (09 January , 2009) [permalink]
    % hdiutil create -ov -imagekey zlib-level=9 -fs HFS+ -format UDZO -scrub -srcfolder /Path/To/The/Goodies fooby.dmg

  • Increasing the length of the "Open Recent" menu (NSDocument->General) (29 November , 2008) [permalink]
    10-15 items not enough for your "Open Recent" menu of a favorite app? Set the app's NSRecentDocumentsLimit default to something more to your liking:
    defaults write com.flyingmeat.acorn NSRecentDocumentsLimit 137
    (thanks to Gus Mueller for this one)

  • emacs registers (emacs->General) (21 November , 2008) [permalink]
    Stick something into a register:
    (select stuff)
    C-x r x 1
    
    where "1" is the register identifier.

    Getting stuff out of a register:

    C-x r g 1
    

  • gdb'ing specific architectures (gdb->Debugging) (31 October , 2008) [permalink]
    With a fat binary (32/64bit), gdb picks the 64 bit version. If you're trying to debug a 32-bit unit test on the command-line though, the 64-bitness of /Developer/Tools/otest gets in the way:
    % gdb /Developer/Tools/otest
    2008-10-31 19:29:50.834 otest[711:813] Error loading
    /blah/blah/blah/build/Debug/Tests.octest/Contents/MacOS/Tests:
    dlopen(/blah/blah/blah/build/Debug/Tests.octest/Contents/MacOS/Tests,
    265): no suitable image found.  Did find:
            /blah/blah/blah/build/Debug/Tests.octest/Contents/MacOS/Tests:
            mach-o, but wrong architecture
    2008-10-31 19:29:50.887 otest[711:813] The test bundle at
    build/Debug/Tests.octest could not be loaded because it is built for a
    different architecture than the currently-running test rig (which is
    running as unknown).
    2008-10-31 19:29:50.904 otest[714:203] *** NSTask: Task create for
    path '/blah/blah/blah/build/Debug/Tests.octest/Contents/MacOS/Tests'
    failed: 8, "Exec format error".  Terminating temporary process.
    You can supply a -arch flag to pick what you want:
    % gdb -arch i386 /Developer/Tools/otest
    And then debug your 32-bit unit test.

  • Balance a tag in SGML mode (emacs->Random) (11 October , 2008) [permalink]
    C-/

  • Making "edit all in scope" work (Xcode->Hacks) (23 August , 2008) [permalink]
    Xcode's "Edit All in Scope" feature is inexplicably tied to visible syntax colorization (actually, only Edit All in Scope for object pointers is tied to this, scalar variables and pointers work fine otherwise). So if you're not getting the Edit All in Scope menu item to enable, make sure "Color indexed Symbols" is turned on in the Xcode "Fonts and Colors" preferences.

    This advice brought to you by a DTS incident.

  • Seeing extended attributes with 'ls' (Unix->General) (25 July , 2008) [permalink]
    Sometimes you see an @ after the directory permissions in an ls -l:
    % ls -l ~/junk/SnapshotRepository.sparseimage
    -rw-r--r--@ 1 markd  markd  135270400 Jul 24 20:38 /Users/markd/junk/SnapshotRepository.sparseimage
    That means there's some extended attributes. use ls -l@ to see them:
    % ls -l@ ~/junk/SnapshotRepository.sparseimage
    -rw-r--r--@ 1 markd  markd  135270400 Jul 24 20:38 /Users/markd/junk/SnapshotRepository.sparseimage
    	com.apple.diskimages.fsck	       20 

  • Changing __MyCompanyName__ (Xcode->Hacks) (25 July , 2008) [permalink]
    You've probably noticed that source files generated from within XCode include a comment block header:
    //
    //  TapDance.h
    //  Groovilicous
    //
    //  Created by markd on 7/25/08.
    //  Copyright 2008 __MyCompanyName__. All rights reserved.
    //
    With the __MyCompanyName__ placeholder. There is no UI to change this, for obvious reasons. (Why would anyone want to easily and conveniently change something they'll otherwise need to edit in each and every source file they create. That's unpossible). The obvious solution is to drop to the terminal and run the straightforward command:
    % defaults write com.apple.Xcode PBXCustomTemplateMacroDefinitions '{"ORGANIZATIONNAME" = "Borkware";}'
    Seemple, no? Zee trick, she is doone.

  • Turning off Xcode's "Undo past save" warning (Xcode->General) (14 July , 2008) [permalink]
    For some reason, Xcode thinks that an undo past the last save is something horrible that you need to be warned about. After living with unstable software, cmd-S is a habit, and undoing past it is No Big Deal. Really. Here's how to turn it off:
    % defaults write com.apple.Xcode XCShowUndoPastSaveWarning NO

  • Making naked memory autoreleased (General->General) (03 June , 2008) [permalink]
    (courtesy of Mike Ash, who fixed some errors in the previous version of this quickie)
    void *tempCopyOf(void *data, NSUInteger size)
    {
       return data ? [[NSData dataWithBytes:data length:size] mutableBytes] : NULL;
    }
    
    OBTW, these techniques will fail under GC. Here's how you'd write a working one under GC:
    void *tempCopyOf(void *data, NSUInteger size)
    {
       void *buffer = NULL;
       if( data ) {
           buffer = NSAllocateCollectable(size, 0);
           memcpy(buffer, data, size);
       }
       return buffer;
    }
    
    Unfortunately I'm not aware of a nice way that works in dual-mode code.

  • Toggle 'screen's visible bell on and off (Unix->General) (27 May , 2008) [permalink]
    Assuming ^t is the hotkey, doing ^t ^g will toggle the visible bell on and off.

  • Multiple Objects in one document (Photoshop->General) (10 May , 2008) [permalink]
    Say you have two Smart Objects from ACR or something, and now you want them into one document so you can do some layer mask nonsense. To get them into one file do this:
    • Open up both files
    • Bring the source file up, shift-drag the layer from the palette
    • Drag into the image area of the target document

  • Opening webview links in the user's default browser. (WebKit->General) (09 May , 2008) [permalink]
    ...
      [someWebView setPolicyDelegate: self];
    ...
    
    - (void) webView:(WebView *)webView
    decidePolicyForNavigationAction:(NSDictionary *)actionInformation
             request:(NSURLRequest *)request
               frame:(WebFrame *)frame
    decisionListener:(id)listener {
        NSURL *url = [request URL];
        if (url != nil) {
            [[NSWorkspace sharedWorkspace] openURL:url];
        }
    
    }  // decidePolicyForNavigationAction
    
    

  • Reverting opened, but unedited files (Perforce->General) (29 April , 2008) [permalink]
     p4 revert -a
    
    will revert all files that haven't actually be edited, leaving the edited opened.

    (Thanks to TVL for this one)

  • Turning off the executable bit in Perforce (Perforce->General) (29 April , 2008) [permalink]
    p4 edit -t text [file_list] 
    p4 submit
    
    (Thanks to TVL for this one)

  • Printing network traffic (Unix->Hacks) (13 March , 2008) [permalink]
    % sudo tcpdump -Atq -s 0 -i en1
    -i en1 will display traffic on your airport card. Use en0 (or nothing, for most systems) for built-in ethernettage.

    You can add a host line to limit output to a particular host

    % sudo tcpdump -Atq -s 0 -i en1 host zombo.com
    (thanks to Dan Jalkut for this one)

  • Eating Brains (Debugging->gdb) (11 March , 2008) [permalink]
    You can turn on Zombies to catch uses of objects after they have been released. Here's an easy way to do it in the gdb console:
      % gdb build/Debug/Snorkfizzle.app/Contents/MacOS/Snorkfizzle
      (gdb) set env NSZombieEnabled=YES
      (gdb) fb -[_NSZombie methodSignatureForSelector:]
      (gdb) run
    
    Then exercise your app and trip the error.

  • Running a window modally (NSWindow->General) (02 March , 2008) [permalink]
      // I am the very modal of a modern major general.
      int blah = [NSApp runModalForWindow:[self window]];
    
    and then elsewhere, like in your OK or cancel button
      [NSApp stopModalWithCode:NSOKButton];

  • Getting OS version from the command line (Unix->Random) (11 February , 2008) [permalink]
    % sw_vers -productVersion
    10.5.1
    

  • Varargs in Objective-C (General->Random) (27 January , 2008) [permalink]
    This processes a nil-terminated sequence of strings:
    - (void) snorgWaffle: (NSString *) start, ... {
    
        va_list argList;
        va_start (argList, start);
    
        NSString *string = start;
    
        while (string != nil) {
            NSLog (@"Done did saw string '%@'", string);
    
            string = va_arg (argList, NSString *);
        }
    
        va_end (argList);
    
    } // snorgWaffle
    and can be called like
    [self snorgWaffle:@"red", @"planet", @"zeitgeist", nil];

  • Launch Services admin tool (Random->Random) (20 December , 2007) [permalink]
    If you need to poke around Lunch Launch Services, use the lsregister tool that lives in/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support

  • Today's date as a string (NSString->General) (04 December , 2007) [permalink]
    The general solution for converting a date to a string is NSDateFormatter. Sometimes you need to generate a date string in a particular format easily. For instance if you need "December 4, 2007", you can use:
    [[NSDate date] descriptionWithCalendarFormat: @"%B %e, %Y" timeZone: nil locale: nil]
    (Thanks to Mike Morton for this one)

  • Binary Searching in a sorted NSArray (NSArray->General) (23 November , 2007) [permalink]
    How do you binary search a sorted NSArray? Use toll free bridging to CFArray which actually has a binary search function:
        NSMutableArray *sortedArray = [NSMutableArray arrayWithObjects: @"Alice", @"Beth", @"Carol",@"Ellen",nil];
        
        //Where is "Beth"?
        unsigned index = (unsigned)CFArrayBSearchValues((CFArrayRef)sortedArray,
                                                        CFRangeMake(0, CFArrayGetCount((CFArrayRef)sortedArray)),
                                                        (CFStringRef)@"Beth",
                                                        (CFComparatorFunction)CFStringCompare,
                                                        NULL);
        if (index < [sortedArray count])
        {
            NSLog(@"Beth was found at index %u", index);
        } else {
            NSLog(@"Beth was not found (index is beyond the bounds of sortedArray)");
        }
        
        //Where should we insert "Debra"?
        unsigned insertIndex = (unsigned)CFArrayBSearchValues((CFArrayRef)sortedArray,
                                                              CFRangeMake(0, CFArrayGetCount((CFArrayRef)sortedArray)),
                                                              (CFStringRef)@"Debra",
                                                              (CFComparatorFunction)CFStringCompare,
                                                              NULL);
        [sortedArray insertObject:@"Debra" atIndex:insertIndex];
        NSLog([sortedArray description]);
    
        //note: NSArray indices and counts were typed as unsigned.  With the move to 64-bit, they are NSUInteger.
        //CFArray indices and counts are CFIndex, which was SInt32 but also will move to 64-bit?
        //Why was it ever signed and will it remain so?
    
    Muchos Thankos to James Hober for this one.

    Gus Mueller chimed in saying that if you use CFArrayBSearchValues, be sure to sort with CFArraySortValues rather than using the Cocoa sorting routines (or at least the comparison) - they treat diacritic marks differently, leading to strange errors. From Gus, a quick objc addition to NSMutableArray:

    - (void) cfStringSort {
       CFArraySortValues((CFMutableArrayRef)self, CFRangeMake(0, [self count]), (CFComparatorFunction)CFStringCompare, NULL);
    }
    

  • Making a Cocoa moby file (General->Random) (29 September, 2007) [permalink]
    % cat /System/Library/Frameworks/Foundation.framework/Headers/*.h > ~/moby
    % cat /System/Library/Frameworks/AppKit.framework/Headers/*.h >> ~/moby
    % chmod 444 ~/moby

  • Sorting with Selectors (NSObject->General) (02 September, 2007) [permalink]
    You can sort mutable arrays by providing a selector that is invoked on each of the elements of the array. I always get confused about NSOrderedAscending / NSOrderedDescending (I think they're actually backwards, but that's just me). Here it is in a nutcase: Given this sort command:
        [themStitches sortUsingSelector: @selector(compareByRowLocation:)];
    
    And this selector on the BWCrossStitch class:
      - (NSComparisonResult) compareByRowLocation: (BWCrossStitch *) thing2;
    
    Figure out which is lesser or greater, and return one of these. Note that self is the object's logical value, not the actual value of the self pointer.
    • NSOrderedAsending if self < thing2
    • NSOrderedDescending if self > thing2
    • NSOrderedSame if self == thing2

  • Cad Macro (ClanLord->Random) (12 August , 2007) [permalink]
    From Seilk. I can never find it when I want it.
    shift-click
    { 
       $any_click 
       if @click.simple_name == "" 
          if @my.right_item == "caduceus" 
             "\use /off\r" 
          end if 
       else if @click.simple_name == @my.simple_name 
          if @my.right_item != "moonstone" 
             "\equip \"moonstone\"\r" 
          end if 
          "\use 3\r" 
       else 
          if @my.right_item != "caduceus" 
             "\equip \"caduceus\"\r" 
          end if 
          "\use " @click.simple_name "\r" 
          message "* Now healing" @click.name 
       end if 
    } 
    

  • Sending email with .mac when port 25 is blocked (Random->Random) (11 August , 2007) [permalink]
    Say you're at a conference, away from your usual ISP, and you're trying to send email, but all port 25 traffic is blocked. Say also you have .mac, for which you keep paying and paying and paying to have a reliable external email address, and sending email is also blocked. .mac (and perhaps other places) use an alternate port (port 587 in .mac's case) which can be use to work around this. Now I can send email, and life is happy.

  • Runing a unit test in ppc mode (Xcode->General) (07 August , 2007) [permalink]
    Say your xcode project happily runs unit tests in i386 mode. You're about to land something that does byte-swapping, and you want to make sure it's sane in PPC mode, and you haven't turned on your G5 in months. You can do this command-line styles on your ICBM (assuming your project doesn't already do ppc and i386 unit tests). Build your test, and use translate to run the powerPC side of the world:
    % xcodebuild -configuration Release -target "Test All" -project Tests.xcodeproj NATIVE_ARCH="i386 ppc"
    
    % /usr/libexec/oah/translate /Developer/Tools/otest build/Release/Tests.octest
    

  • Running shell command pasting result back into the buffer (emacs->General) (19 July , 2007) [permalink]
    So to run uuidgen, for instance:

    C-U M-! ret uuidgen ret

  • Don't show file names with a multi-file grep (Unix->General) (23 May , 2007) [permalink]
    use the -h flag:
    % grep -h chicken ~/Documents/ircLogs/FreeNode/2007*/#macsb*

  • Put a string on the pasteboard (NSString->Random) (22 May , 2007) [permalink]
    Here's a category for easily putting a string on the paste|clipboard:
    @implementation NSString (PasteboardGoodies)
    
    - (void) sendToPasteboard
    {
            [[NSPasteboard generalPasteboard] 
                declareTypes: [NSArray arrayWithObject: NSStringPboardType]
                owner:nil];
            [[NSPasteboard generalPasteboard]
                setString: self
                forType: NSStringPboardType];
    } // sendToPasteboard
    
    @end // PasteboardGoodies
    
    Thanks to Dan Jalkut for this tip.

  • Reverting all files (Perforce->General) (22 May , 2007) [permalink]
    % p4 revert -c default ...

  • Breaking on exceptions (gdb->General) (05 May , 2007) [permalink]
    It can be annoying tracking down the cause of thrown exceptions in Cocoa. you get a notice like 2007-05-05 17:18:00.702 QueenStitcher[2804:117] *** Assertion failure in -[NSColorWell setColor:], NSColorWell.m:497, u suk l0s3r, and then the runloop happily runs again, giving you no clue where the problem is. I tell gdbto always break on Cocoa exceptions:
    fb -[NSException raise]
    fb objc_exception_throw()
    For maximal enjoyment, add these two lines to your ~/.gdbinit file, so they'll get set no matter how you invoke gdb (no need to add these to every single project, for instance).

    I've been told VoiceOver uses exceptions heavily, so if you're doing VoiceOver development, these breaks may cause you pain.

  • 'join' an array of strings into a single string (NSString->General) (05 May , 2007) [permalink]
    NSArray *chunks  = ... get an array, say by splitting it;
    string = [chunks componentsJoinedByString: @" :-) "];
    would produce something like
    oop :-) ack :-) bork :-) greeble :-) ponies
    

  • Stripping out newlines from a string (NSString->General) (05 May , 2007) [permalink]
    So you have an NSString and want to yank out the newlines. You can do a splitand join, like in scripting languages, or you can make a mutable copy and manipulate that:
        NSMutableString *mstring = [NSMutableString stringWithString:string];
        NSRange wholeShebang = NSMakeRange(0, [mstring length]);
    
        [mstring replaceOccurrencesOfString: @"
    "
                 withString: @""
                 options: 0
                 range: wholeShebang];
    
        return [NSString stringWithString: mstring];
    (this can also be used for generic string manipulations, not just stripping out newlines).

    This technique takes half the time (at least) of split/join. But probably not enough to make an impact. In a simple test, split/join took 0.124 seconds to strip 36909 newlines in a 1.5 meg textfile, and 0.071 seconds to do the same.

  • printf'ing / NSLogging strings without a terminating zero byte (General->Random) (04 May , 2007) [permalink]
      printf ("hello %.*s\n", 5, "there is no good going on");
      NSLog (@"hello %.*s\n", 5, "there is no good going on");
    results in
    hello there
    2007-05-04 09:14:15.575 printf[4914] hello there

    Similarly, something like printf ("hello %*.*s\n", 10, 5, "florgsnorgle"); will right-justify 'florg' in a field of 10 characters.

    (Thanks to TVL for this goodie)

  • 'split' a string into an array (NSString->General) (09 April , 2007) [permalink]
      NSString *string = @"oop:ack:bork:greeble:ponies";
      NSArray *chunks = [string componentsSeparatedByString: @":"];

  • Sanity checking an XML file (Unix->General) (20 March , 2007) [permalink]
    % xmllint -noout kipple.xml Handy for a quick check after hand-editing a file.

  • Changing a file's modification date (Unix->Random) (16 March , 2007) [permalink]
    Sometimes you're doing work which uses a file's modification time to decide whether you want to do something (like don't process today's log file, or remove a really old file). You could use a time machine to test this, or use touch. You can specify a specific date or time using the format [[CC]YY]MMDDhhmm[.SS]]. Here's an example with alternating bolds to make it easier to read:
    % touch -t 200703141536 snork.waffle
    
    % ls -l snork.waffle
    -rw-r--r--   1 markd  markd  298 Mar 14 15:36 snork.waffle
    

  • Making the VPN survive fast user switching. (Hacks->Hacks) (12 March , 2007) [permalink]
    Testing admin vs non admin user scenarios while connected to the mothership VPN is a pain. Heres a way to modify the system configuration plist to make the VPN connection survive fast user switching.

    Open up Internet Connect, select your VPN icon in the toolbar, and choose options from the Connect menu. Uncheck "Disconnect when switching user accounts".

  • Setting compiler flags on a per-file basis (Xcode->General) (09 March , 2007) [permalink]
    Sometimes you need to set compiler flags on a per-file basis, like you need to suppress a warning in one place or set a one-off #define, but not for the entire project. You can set these flags in the build tab of the Get Info window of the source file in the target's compile sources build phase. If you get info on the source file in other places in Xcode, there's no build tab, and you're left with that "Am I crazy? I know I've seen that setting somewhere before, but where is it? I better go back to listening to Finnish polkas 24/7 and give up this software thing" kind of feeling.

  • Seeing the files in a zip archive (Unix->General) (08 March , 2007) [permalink]
    % unzip -l snorgle.zip

  • Making naked memory autoreleased (Hacks->General) (28 February , 2007) [permalink]
    From the devious mind of Rainer Brockerhoff : given a pointer + length, dynamically allocate a copy and make it autoreleased, without (directly) involving cocoa objects. One handy usage: giving a plugin a copy of some struct, but be protected against the plugin messing it up.
    static void *tempCopyOf(void *data,UInt32 size) {
        void *buffer = NULL;
        if (data) {
            buffer = malloc(size);
            if (buffer) {
                bcopy(data,buffer,size);
                [NSData dataWithBytesNoCopy: buffer  length: size  freeWhenDone: YES];
            }
        }
        return (buffer);
    }
    You can get really fancy and assign buffer to calloc(1, size) if you want to give it "pass NULL to get a zero-filled buffer back" semantics.

    Also note this doesn't play well with garbage collection - caveat nerdor. (Thanks to Ken Ferry for that note)

  • Converting from a path to an FSRef (General->Random) (27 February , 2007) [permalink]
      NSString *pathString = ... whatever ...;
    
      FSRef ref;
      status = FSPathMakeRef ((const UInt8 *)[pathString fileSystemRepresentation],
                              &ref, NULL);
    
      if (status != noErr) {
          NSLog (@"bummer.  couldn't make FSREf from path '%@'",
                 pathString);
      }

  • Derezzing resource files (General->Random) (21 February , 2007) [permalink]
    I needed to derez a resource file, with the data living in the resource fork, and get editable STR and STR# entities. Here's one way to do it, with the moving pieces in bold.
    % /Developer/Tools/DeRez -useDF  ./blarg.rsrc  /Developer/SDKs/MacOSX10.4u.sdk/Developer/Headers/FlatCarbon/MacTypes.r  > oopack2
    And the reverse process is like:
    % /Developer/Tools/Rez -o blah.rsrc -useDF  /Developer/SDKs/MacOSX10.4u.sdk/Developer/Headers/FlatCarbon/MacTypes.r oopack2

  • Extracting PDF text on the cheap (Random->Hacks) (19 February , 2007) [permalink]
    Sometimes you need the text from a PDF, and copy-pasting from Preview isn't terribly reliable. If you really just need text and no formatting, Spotlight can help you out:
    % /usr/bin/mdimport -d2  ../Book.pdf >& oopack.txt
    And edit out the little bit of extra metadata output.

  • Changing a working tree's repository location (Subversion->Hacks) (19 February , 2007) [permalink]
    Sometimes your subversion repository moves (like if you're using a private one and the machine changes addresses). Here's how to repoint a working tree to the new location (handy if there's outstanding changes that are a pain to move over to a fresh checkout)
    % svn switch --relocate http://from-address.flongswozzle.net http://to-address.borkware.com
    Muchos thankos to Lucas Eckels for the tip.

  • Defaults-writing an array (General->General) (08 February , 2007) [permalink]
    % defaults write com.borkware.snongflozzle ookook -array thing1 thing2 thing3

  • Reducing verbiage on web pages to make them readable. (Random->General) (29 January , 2007) [permalink]
    In #macsb IRC one day I was complaining about a rumor site blog posting that was hugely long and nearly incomprehensible. I was pointed to the summarization service as a way of reducing the brainpower needed to figure out what was going on:
    • Select all the text
    • Go to the services menu and select summarization service
    • You'll get a window with a slider at the bottom. Move that down all the way to the left
    • Amazingly, with 9/10 of blog posts it works REALLY well.
    (thanks to Chris Forsythe for this one)

  • Using NSInvocation (General->General) (17 January , 2007) [permalink]
    When you have a target and a selector, it's pretty easy to invoke the selector on the target if you're passing one or two parameters, with performSelector:, performSelector:withObject:, and so on. If you need to pass three arguments, or things that aren't objects, then you need to use NSInvocation.

    In this case, the selector being called takes two arguments, one of which is an object, the other is an NSTimeInterval. The atIndex: jazz starts with 2 so that the self parameter and the selector can be passed to the method.

      NSMethodSignature *signature = [target_ methodSignatureForSelector:selector_];
    
      NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
      [invocation setSelector:selector_];
      [invocation setTarget:target_];
      [invocation setArgument:&self
                  atIndex:2];
      [invocation setArgument:&lastWait_
                  atIndex:3];
    
      [invocation invoke];

  • Non-chunky high-DPI image drawing (NSImage->General) (15 January , 2007) [permalink]
    If you load NSImages from random files and draw them larger than they say they are, sometimes you get a really chunky, pixellated display for images that have a high DPI rather than a smooth interpolation (or even using all those extra pixels due to the high DPI). This is because (I think) that the image says that it's 100x100, even though you have 1000x1000 pixels available, and Cocoa decides to scale up only 100x100 pixels.

    One way to hack around it is to tell the image to use the pixel size of the underlying image representation:

        NSImage *image;
        image = [[NSImage alloc] initWithContentsOfFile: path];
    
        NSBitmapImageRep *rep = [[image representations] objectAtIndex: 0];
        // If you think you might get something other than a bitmap image representation,
        // check for it here.
    
        NSSize size = NSMakeSize ([rep pixelsWide], [rep pixelsHigh]);
        [image setSize: size];

  • Running a specific unit test from the command line (Xcode->General) (12 January , 2007) [permalink]
    % /Developer/Tools/otest -SenTest  ClassName ./build/Debug/TheUnitTest.octest

  • Truncating text in the middle of a string (NSTextView->General) (04 January , 2007) [permalink]
    Sometimes you see text that is of the form "Some Gro...eral Fish", with the middle truncated but the ends still readable. You can get this effect yourself with:
    [[textfield cell] setLineBreakMode: NSLineBreakByTruncatingMiddle]
    
    (Thanks to Daniel Jalkut for this one)

  • Making a moby file out of a hierarchy (General->General) (27 November , 2006) [permalink]
    % find . -name "*.h" -print -exec cat {} \; > ~/moby-file.h
    

  • Easy command-line argument handling (General->General) (21 November , 2006) [permalink]
    You can use NSUserDefaults to sniff your command line. So using something like this:
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        gridType = [defaults objectForKey: @"gridType"];
    
    Will have the value of "flarn" whether you do something like
    % defaults write com.borkware.BorkStitch gridType flarn
    or
    % ./build/Debug/BorkStitch.app/Contents/MacOS/BorkStitch -gridType flarn

  • Easier Development of Screen Savers (Screen Savers->General) (14 October , 2006) [permalink]
    When you're writing a screen saver, do you find yourself often copying the basted thing to your ~/Library/Screen Savers folder? If so, you can make a symbolic link that points to your screen saver bundle, and that will automatically get used whenever you engage the screen saver engine. e.g.
    % cd ~/Library/Screen Savers
    % ln -s ~/Projects/MonkeySaver/build/Debug/MonkeySaver.saver .
    

  • tar + xargs for huge numbers of files (Unix->General) (09 October , 2006) [permalink]
    If you have too many files to add to a tarball, you can run into the shell's command limitation. If you use xargs + tar cf, you'll not get all of your files added to the tarball. Use tar's rf command to append to an archive rather than creating one:
    % find . -name "*.yuck" -print0 | xargs -0 tar rvf oop.tar
    
    -print0 (zero) tells find to output the filenames with trailing NUL characters (rather than newlines), and -0 tells xargs to use a NUL as its input separator, rather than newlines/spaces. The upshot is that you can handle filenames with spaces in them.

    Thanks to Ben Cox for the -print0 / -0 suggestion.

  • Turning off font-lock mode everywhere (emacs->General) (30 September, 2006) [permalink]
    (global-font-lock-mode -1)

  • Turning off scroll-to-end in shell-mode (emacs->General) (30 September, 2006) [permalink]
    (setq comint-scroll-show-maximum-output nil)

  • Putting an NSXMLDocument into a text view (NSXML->General) (25 August , 2006) [permalink]
        NSData *blah = [xmldocument XMLDataWithOptions: NSXMLNodePrettyPrint];
        NSString *snork = [[NSString alloc] initWithData: blah
                                            encoding: NSUTF8StringEncoding];
        NSAttributedString *arrrgh;
        arrrgh = [[NSAttributedString alloc] initWithString: snork];
    
        [[xmlTextView textStorage]
            setAttributedString: [arrrgh autorelease]];
    

  • Subversion over ssh (Subversion->General) (12 August , 2006) [permalink]
    To access a repository that lives over ssh (vs http or file), use the svn+ssh protocol thingie in the commands, like
    % svn mkdir -m "initial revision" svn+ssh://borkware.com/path/to/svnroot/thingie

  • Turning off Spotlight (Random->General) (11 August , 2006) [permalink]
    % sudo mdutil -i off /

  • Enabling buttons based on tableview selection (Bindings->NSTableView) (04 August , 2006) [permalink]
    Bind to your array controller selection, using @count.

  • CGShading (Graphics->General) (22 July , 2006) [permalink]
    CGShading lets you do color ramps. Setting one up is a little complicated, juggling a couple of CG data structures and writing the ramping function.
        float domain[2] = { 0.0, 1.0 };     // 1-in function
        float range[8] = { 0.0, 1.0,        // N-out, RGBA
                           0.0, 1.0,
                           0.0, 1.0,
                           0.0, 1.0 };
        CGFunctionCallbacks callbacks = { 0, evaluate, NULL };
    
        CGFunctionRef shaderFunction;
        shaderFunction = CGFunctionCreate (self,    // info / rock / context
                                           1,       // # of inputs for domain
                                           domain,  // domain
                                           4,       // # of inputs for range
                                           range,   // range
                                           &callbacks);
    
        CGColorSpaceRef deviceRGB;
        deviceRGB = CGColorSpaceCreateDeviceRGB ();
    
        CGShadingRef shader;
        shader = CGShadingCreateAxial (deviceRGB,       // colorspace
                                       cgpoint(start),  // start of axis
                                       cgpoint(end),    // end of axis
                                       shaderFunction,  // shader, 1-n, n-out
                                       NO,              // extend start
                                       NO);             // extend end
    
        CGContextSaveGState (context); {
            NSRect bounds = [self bounds];
            CGContextClipToRect (context, cgrect(bounds));
            CGContextDrawShading (context, shader);
        } CGContextRestoreGState (context);
    
        [self drawSpotAt: start  size: 4];
        [self drawSpotAt: end  size: 4];
    
        CGFunctionRelease (shaderFunction);
        CGColorSpaceRelease (deviceRGB);
        CGShadingRelease (shader);
    And the evaluator function is given an array of inputs and outputs. Use the in value(s) (which run from your domain's start-to-finish values) to generate the out values (which should be in the range's start-to-finish values):
    static void evaluate (void *info, const float *in, float *out)
    {
        float thing;
        thing = in[0];
    
        out[0] = thing;
        out[1] = thing;
        out[2] = thing;
        out[3] = 1.0;
    
    } // evaluate

  • Getting a CGContext from Cocoaland (Graphics->General) (22 July , 2006) [permalink]
    You can use CG (CoreGraphics) functions inside of a Cocoa view - pass the graphics port of the current context to the CG functions, like this:
    #define cgrect(nsrect) (*(CGRect *)&(nsrect))
    
    - (void) drawRect: (NSRect) rect
    {
        NSRect bounds = [self bounds];
    
        NSGraphicsContext *cocoaContext = [NSGraphicsContext currentContext];
        CGContextRef context = (CGContextRef)[cocoaContext graphicsPort];
    
        CGContextSetLineWidth (context, 5.0);
    
        CGContextBeginPath(context); {
            CGContextAddRect (context, cgrect(bounds));
            CGContextSetRGBFillColor (context, 1.0, 0.9, 0.8, 1.0);
        } CGContextFillPath(context);
    
    } // drawRect

  • Using CGLayers (Graphics->General) (22 July , 2006) [permalink]
    CGLayer is a Tiger (and beyond) feature that will cache Quartz operations. Kind of like a PICT for CG. Make a new layer based on the context you're going to be drawing it in, then get a context from the layer, and draw into that. So something like this:
    - (void) makeLayerInContext: (CGContextRef) enclosingContext
    {
        layer = CGLayerCreateWithContext (enclosingContext, CGSizeMake(100, 100),
                                          NULL); // options - unused in Tiger
        CGContextRef context;
        context = CGLayerGetContext (layer);
    
        // .. and do your drawing
    
    } // makeLayer
    
    And then to draw the layer at a particular point (like replicating it a bunch of different points as done here):
        for (i = 0; i < pointCount; i++) {
            CGContextDrawLayerAtPoint (context, locations[i], layer);
        }
    

  • Macro recording (emacs->General) (11 July , 2006) [permalink]
    C-x ( : start recording keyboard macro
    C-x ) : stop recording keyboard macro
    C-x e : replay current keyboard macro

  • Perl breaks in weird and wonderful(?) ways (Unix->General) (03 July , 2006) [permalink]
    Perl 5.8 uses unicode internally by default, which apparently causes trouble for some big perl packages (like SpamAssassin's makefile getting totally trashed when you create it). Set the LANG environment variable to be en_US to make it happier.

  • Deatching another screen session. (Unix->General) (30 June , 2006) [permalink]
    Sometimes if you have an unclean disconnect, screen can still be attached and you get the smackdown:
    % screen -r
    There is a screen on:
            8395.pts-0.vikki    (Multi, attached)
    You can boot off that other loser by using:
    % screen -d 8395.pts-0.vikki
    and then doing screen-r again

  • Changing the 'screen' hotkey (Unix->Tools) (28 June , 2006) [permalink]
    Running emacs inside of screen is made difficult because both want to use C-A for something important. C-O (AFAIK so far) isn't too useful for my use of emacs, so I use that for screen now:
    screen -e^Oo emacs

  • Rejoining a disconnected screen session (Unix->Tools) (28 June , 2006) [permalink]
    screen -r

  • Fixing emacs backspace in screen (emacs->General) (28 June , 2006) [permalink]
    When running emacs insde of screen, screen helpfully turns the backspace/delete key into "^[[3~", which gets turned into a forward-delete. Unfortunately, just bashingdeletechar into backward-delete-char-untabify causes backspace in incremental search to cancel the search, which is annoying.

    One option is to set the TERM env var to rxvt:

    % setenv TERM rxvt
    Before cranking up screen.

  • Next value from a sequence (Postgresql->General) (20 June , 2006) [permalink]
    insert into blah (id, stuff) 
           values (nextval('sequence_name'), 'stuff');

  • Printing wide character strings (gdb->General) (19 June , 2006) [permalink]
    gdb won't by default let you print wide character strings. Here is a little bit of gdb code that'll let you print them. In case that page moves, here is the relevant stuff. Paste this into your .gdbinit and then you can use wchar_print:
    define wchar_print
            echo "
    
            set $i = 0
            while (1 == 1)
                    set $c = (char)(($arg0)[$i++])
                    if ($c == '\0')
                            loop_break
                    end
                    printf "%c", $c
            end
    
            echo "
    
    end
    
    document wchar_print
    wchar_print <wstr>
    Print ASCII part of <wstr>, which is a wide character string of type wchar_t*.
    end
    

  • Daemontools controls (Unix->General) (16 June , 2006) [permalink]
    # svc -d /service/whatever - Bring the server down

    # svc -u /service/whatever - Start the server up and leave it in keepalive mode.

    # svc -o /service/whatever - Start the server up once. Do not restart it if it stops.

    # svc -t /service/whatever - Stop and immediately restart the server.

    # svc -k /service/whatever - Sends the server a KILL signal. This is like KILL -9. If svc -t fails to fully kill the process, use this option.

    (Thanks to the OpenACS documentation)

  • Unladen Swallows? (VoodooPad->AppleScript) (08 June , 2006) [permalink]
    tell application "VoodooPad"
    	taunt
    end tell

  • Break on szone_error not working (gdb->General) (06 June , 2006) [permalink]
    Sometimes when you have memory corruption issues, the malloc library happily informs you:
    Borkdoku(11062,0xcec0600) malloc: *** error for object 0xd109010: 
       incorrect checksum for freed object - object was probably modified 
       after being freed, break at szone_error to debug
    Which is fine and dandy, but it lies. I've never gotten szone_error to actually do anything. Try breaking on malloc_printf instead.

  • Weak Linking in a Plugin (Tools->General) (05 June , 2006) [permalink]
    I've got some useful utilities in a .c file that I use for some debugging things. And I'm also writing a plugin that will go into an app I don't control. I also have a test harness that I can load the plugin and do effective debugging. This debugging file has some static variables that it uses to control things, like whether to emit log messages, or do other diagnoses.

    The problem is, if I include the usefulStuff.c in my plugin and my test harness, there are two copies of the static variables, and the test harness can't control the plugin. If I don't include usefulStuff.c in the plugin I get link errors. If I don't declare as weak linked the functions I use, I'll get errors when the final program loads the plugin. Sucks to be me.

    Here's one way of doing it (which is kinda hacky, but after spending a day inside of the ld man page, and other pain, the fact it works is good enough for me for right now).

    In the source file for the plugin that uses stuff from usefulStuff:

    Declare the function to be weak:

    extern void BWDebugLog (int blah, char *blah) __attribute__((weak_import));
    (you can also do this in your header files. In this case, I didn't want to touch the header)

    Before you use the function, make sure it's not NULL. Note there's no trailing () after the function name.

    if (BWDebugLog != NULL) {
        BWDebugLog (23, "stuff");
    }
    In the Xcode project for the plugin

    Add the flags -flat_namespace and -undefined dynamic_lookup to the "Other Linker Flags" (a.k.a. OTHER_LDFLAGS). The flat namespace lets the symbols be found in the test harness when the plugin is loaded. The undefined dynamic_lookup means to suppress warnings about undefined symbols. This could conceivably mask errors, but it's no worse than ZeroLink.

    In the Xcode project for the test harness

    Add usefulStuff.c, and turn on the "Preserve Private External Symbols" checkbox (a.k.a -keep_private_externs). That turns the symbol BWDebugLog (and others) into exported symbols that'll be visible to the plugin. Otherwise the plugin will never get past that != NULL check earlier.

    Once all that's done, my plugin loads into the test harness and can get controlled. It can be loaded into the Real App without undefined symbol errors.

  • Setting variables when loading a file (emacs->General) (02 June , 2006) [permalink]
    So say you're working on a project with two-space indents, but most of your other work happens with four-space indents. If the two-space crowd is amenable, add this to the bottom of the file:
    /* For the emacs weenies in the crowd.
    Local Variables:
       c-basic-offset: 2
    End:
    */

  • Debugging unit tests from the command-line (Xcode->General) (29 May , 2006) [permalink]
    First, find the .octest file of interest:
    % find . -name "*.octest" -print
    ./build/Debug/Tests.octest
    Then gdb Tools/otest:
    % gdb /Developer/Tools/otest
    Then run it with the name of the bundle:
    (gdb) run ./build/Debug/Tests.octest

  • Format of new pages (VoodooPad->General) (28 May , 2006) [permalink]
    Make a page called NewPageTemplate. Use $title$ for the page term.

  • Giving the event loop some love (General->General) (24 May , 2006) [permalink]
    Say you're in a callback environment in the main thread, but need to update the UI, like to update a progress meter. You can give the runloop a chance to do one flip by doing:
    void giveSomeLove ()
    {
        // give the app some love so it'll update the window
        [[NSRunLoop currentRunLoop] runUntilDate: [NSDate distantPast]];
    } // giveSomeLove

  • Using an NSOpenPanel (General->General) (24 May , 2006) [permalink]
        NSOpenPanel *panel = [NSOpenPanel openPanel];
    
        [panel setPrompt: @"Stuff for the Choose Button"];
    
        [panel beginSheetForDirectory: nil
               file: nil
               types: [NSArray arrayWithObject: @"buf"] // or other file types
               modalForWindow: window
               modalDelegate: self
               didEndSelector: @selector(openPanelDidEnd:returnCode:contextInfo:)
               contextInfo: nil];
    and the didEndSelector implementation looks kinda like this:
    - (void) openPanelDidEnd: (NSOpenPanel *) sheet
                  returnCode: (int) returnCode
                 contextInfo: (void *) context
    {
        if (returnCode == NSOKButton) {
            NSArray *fileNames = [sheet filenames];
    
            NSLog (@"wooOOooot! %@", [fileNames objectAtIndex: 0]);
        }
    
    } // openPanelDidEnd

  • show predefined preprocessor macros (General->General) (17 May , 2006) [permalink]
    % gcc -E -dM - </dev/null

  • Using libgmalloc in gdb (gdb->General) (01 May , 2006) [permalink]
    libgmalloc puts guard pages at the end of malloc'd blocks of memory, letting you catch buffer overruns. (This will hugely inflate your program's working set, and may lead to swapping) To turn on libgmalloc in gdb, do this:
    (gdb) set env DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib

  • Converting a Fixed to a float (Random->General) (01 May , 2006) [permalink]
    float blah = FixedToFloat(someFixedvalue);
    other goodies in FixMath.h

  • Grepping for flags (Unix->General) (23 April , 2006) [permalink]
    Sometimes you want to grep for something like "-H", but don't want it to be interpreted as a grep flag. The -e option to the rescue:
    % grep -e -H filename
    

  • Running a pre-canned applescript (AppleScript->General) (21 April , 2006) [permalink]
    Here's a way to run a 'fire and forget' Applescript that lives in your application bundle.
    #define runScriptName @"checknewnow"
    #define runScriptType @"scpt"
    
    
    - (IBAction)runScript:(id)sender
    {
        /* Locate that darn thing*/
        NSString *scriptPath = [[NSBundle mainBundle]
                                   pathForResource: runScriptName
                                   ofType: runScriptType];
        NSURL *scriptURL = [NSURL fileURLWithPath: scriptPath];
    
        NSAppleScript *as = [[NSAppleScript alloc]
                                initWithContentsOfURL: scriptURL
                                error: nil];
        [as executeAndReturnError: NULL];
        [as release];
    }
    (Thanks to of Chris "The_Tick" Forsythe)

  • Finding 'self' on Intel (gdb->General) (18 April , 2006) [permalink]
    (gdb) po *(int*)($ebp+8)

  • Displaying four-character ints (gdb->General) (17 April , 2006) [permalink]
    Old-school Mac programming (and Quicktime, and other places) use four-character ints, things like 'bork'. You can have gdb print them out if you need to look at one or two of them:
    (gdb) print/T 1936746868
    $4 = 'spit'
    
    (thanks to Daniel Jalkut for the print/T trick)

  • Using awk to extract the n'th column (Unix->General) (21 March , 2006) [permalink]
    nm outputs a three-column format. I needed to get the set of defined symbols (in particular those that start with __, in tracking down a C++ linking problem), which is the third column. awk is good for that. Use $N to get the nth column (zero-index). This pipeline did the trick:

     nm ./oopack.o | awk '{print $2}' | sort | grep __
    
    (Thanks to DougEDoug for the pointer)

  • Mysterious duplicated symbols (Xcode->General) (21 March , 2006) [permalink]
    This killed a big chunk of time, so I figured I better record it here. While building a C++ shared library, I was getting errors like:

    ld: multiple definitions of symbol __ZN13CaptureWidgetD2Ev
    /Users/blah/blah/build/./capture.build/Debug/capture.build/Objects-normal/ppc/capturewidget-F17F43C0.o definition of __ZN13CaptureWidgetD2Ev in section (__TEXT,__text)
    /Users/blah/blah/build/./capture.build/Debug/capture.build/Objects-normal/ppc/capturewidget-F17F43C0.o definition of __ZN13CaptureWidgetD2Ev in section (__TEXT,__text)

    This is especially annoying, because the same object file is listed as having a duplicated symbol. If you take out the file from being compiled, you get undefined symbols for that particular source file, and if you put it back in, you get duplicated symbols.

    Turn out the problem is that Xcode (somehow) added the C++ file to the "Build Sources" phase of the target. It happily generated two identical object files, and proceded to link them (hence the error), but doesn't get the reporting information correct (hence saying that both symbols come from the same file)

  • Running a unit-test from the command line (Xcode->General) (21 February , 2006) [permalink]
    % /Developer/Tools/otest path/to/build/Unittest/TheUnit Test.octest

  • Recursively adding directories (CVS->General) (17 February , 2006) [permalink]
    To recursively add stuff in CVS:
    % find . -type d -print | grep -v CVS | xargs cvs add
    % find . -type f -print | grep -v CVS | xargs cvs add
    
    The first adds the directories, the second adds the files. Filenames with spaces in them won't be added, and it won't do the Right Thing with -kb for binary files.

  • Changing a dylib's install name (Tools->General) (16 February , 2006) [permalink]
    A dynamic library has an 'install name', which is where the library will assume it will be installed. For things like frameworks that will be stored in an application bundle, the install name has something like @executable_path/../blah. Sometimes you get a library from someone else (or something generated by a gigantic configure script) and need to change the install name. The install_name_tool will do that for you. Say I had a library, libbork.dylib, that will end up being placed side-by-side with the executable of a cocoa app, this is how I would fix it:
    % install_name_tool -id @executable_path/libbork.dylib ./libbork.dylib
    

  • Caveman debugging in both Safari and Dashboard (Dashboard->General) (13 February , 2006) [permalink]
    It'd be too convenient to have a uniform mechanism to perform caveman debugging of widgets in both Safari-preview mode (where you can use window.console.log) and Dashboard mode (where you can't). Luckily (?), window.alert in Dashboard will log to the console in Dashboard, but shows an alert in safari.

    So, combine the two for maximal pleasure:

    function cavemanLog(message) {
      
      if (window.widget) {
        // Won't display an error box, but will show in the console log.
        window.alert(message);
    
      } else {
        // Send output to the javascript console.
        window.console.log(message);
      }
    
    } // cavemanLog

  • Adding a column to a table (Postgresql->General) (03 January , 2006) [permalink]
    alter table pfo_survey_response_2006 add column section text

  • console logging in Safari (Safari->General) (16 December , 2005) [permalink]
      if (window.console) {
        window.console.log ("ook1");
      }
    
    (window.console exists in Safari, but not in Dashboard)

  • Watching all notifications (Notifications->General) (12 December , 2005) [permalink]
    There's three notification centers - one for the app, one for the workspace, and the distributed notification center. Here's how to watch everything:
    #import <Cocoa/Cocoa.h>
    #import <stdio.h> // for printf()
    
    @interface NotificationSpy
    {
    }
    
    + (void) startSpying;
    + (void) stopSpying;
    
    @end // NotificationSpy
    
    
    // prevent us from adding ourselves multiple times
    
    static BOOL g_spying;
    
    
    @implementation NotificationSpy
    
    // turn on listening for all notifications.
    
    + (void) startSpying
    {
        if (!g_spying) {
            NSNotificationCenter *center;
    
            // first the default notification center, which is all
            // notifications that just happen inside of our program
    
            center = [NSNotificationCenter defaultCenter];
            
            [center addObserver: self
                    selector: @selector(observeDefaultCenterStuff:)
                    name: nil
                    object: nil];
    
            // then the NSWorkspace notification center, which tells us things
            // like other applications launching, and the machine sleeping
            // and waking
    
            center = [[NSWorkspace sharedWorkspace]
                         notificationCenter]; 
    
            [center addObserver: self
                    selector: @selector(observeWorkspaceStuff:)
                    name: nil
                    object: nil];
    
            // and lastly the distributed notification center.  This is a
            // global (to the computer) notification center.  You can find
            // out when a different program gets focus, or the sound or
            // screen brightness changes.
    
            center = [NSDistributedNotificationCenter 
                         notificationCenterForType: NSLocalNotificationCenterType];
    
            [center addObserver: self
                    selector: @selector(observeDistributedStuff:)
                    name: nil
                    object: nil];
    
            g_spying = YES;
        }
    
    } // startSpying 
    
    
    // remove us as observers
    
    + (void) stopSpying
    {
        if (!g_spying) {
            NSNotificationCenter *center;
    
            // take us off the default center for our app
            center = [NSNotificationCenter defaultCenter];
            [center removeObserver: self];
    
            // and for the workspace
            center = [[NSWorkspace sharedWorkspace] 
                         notificationCenter];
            [center removeObserver: self];
    
            // and finally off of the machine-wide center
            center = [NSDistributedNotificationCenter 
                         notificationCenterForType: NSLocalNotificationCenterType];
            [center removeObserver: self];
    
            g_spying = NO;
        }
    
    } // stopSpying
    
    
    
    + (void) observeDefaultCenterStuff: (NSNotification *) notification
    {
        // QuietLog can also be found in the quickies
        QuietLog (@"default: %@", [notification name]);
    } // observeDefaultCenterStuff
    
    
    
    + (void) observeDistributedStuff: (NSNotification *) notification
    {
        QuietLog (@"distributed: %@", [notification name]);
    } // observeDistributedStuff
    
    
    
    + (void) observeWorkspaceStuff: (NSNotification *) notification
    {
        QuietLog (@"workspace: %@", [notification name]);
    } // observeWorkspaceStuff
    
    
    @end // NotificationSpy

  • Preventing Safari from displaying PDFs (WebKit->General) (10 December , 2005) [permalink]
    I loathe using Safari to read PDFs. To tell Safari to stop it, try doing
    % defaults write com.apple.Safari WebKitOmitPDFSupport -bool YES
    if you have the misfortune of having the Acrobat Reader plug-in, you can nuke /Library/Internet Plug-Ins/AdobePDFViewer.plugin

  • Runing a widget without installing it (Dashboard->General) (08 December , 2005) [permalink]
    When you double-click a widget or open it from the terminal, you get asked if you want to install it (which will move your widget to ~/Library/Widgets, which is really annoying when it drags it out of your development area. When faced with the dialog, hold down command and option to get a "Run" button. That'll run the widget in-pace. If you tun on the devmode:
    % defaults write com.apple.dashboard devmode YES
    You can drag widgets out of the dashboard area and have them on-screen. Cmd-R will reload the widget.

  • Displaying archived web data in a WebView (WebKit->General) (05 December , 2005) [permalink]
    WebArchive *archive = ... get from somewhere...;
    
    WebFrame *frame = [webView mainFrame];
    [frame loadArchive: webarchive];

  • KVO Array controller gotcha (Bindings->General) (30 November , 2005) [permalink]
    If you're doing KVO and don't override observeValueForKeyPath:ofObject:change:context:, (or you do override it but don't handle your callbacks) you'll generally get an exception. This trains you to do it right and never call super for the callbacks you're handling, or you'll get an exception.

    Except if you've added KVO to a subclass of NSArrayController (and possibly all controller types), and don't call super'sobserveValueForKeyPath:ofObject:change:context:, bindings won't work at all, with no warning/notice/nothing. (Courtesy of Duncan Wilcox)

  • Stopping a chirping G5 (Hacks->Random) (29 November , 2005) [permalink]
    Some (many? all?) G5s make a quiet chirping sound at one-second intervals, like a quiet cricket. It might also chirp when dragging windows or doing something with expose. If that bothers you (like it bothered me), go download CHUD (which you should have already), go to the Processor system preference panel, and turn off "allow nap". That may shorten the life of your machine. But what that means, I have no idea.

  • Enabling the Safari debug menu (Safari->General) (27 November , 2005) [permalink]
    defaults write com.apple.Safari IncludeDebugMenu 1

  • NSTimers and NSTerminateLater (NSTimer->General) (21 November , 2005) [permalink]
    If your application has an open TCP connection to a server and you receive an applicationShouldTerminate: message, you're likely to want to returnNSTerminateLaterso that you can first gracefully shut down the connection before quitting.

    There is a gotcha: returning NSTerminateLater stops the main runloop, so your NSTimers will stop working from that point on. Thus, if you were depending on a timer firing to finish up your shut-down process, you'll never see it, and you'll hang. The solution is to return NSTerminateCancel, then do whatever you need to do and then terminate yourself manually. (Thanks to Larry Gerndt for this one!)

  • Tracing message sends using gdb (Debugging->gdb) (31 October , 2005) [permalink]
    b objc_msgSend
    comm
    silent
    printf "%c[%s %s]\n", $r3&&((id)$r3)->isa->info&2?'+':'-', $r3?((id)$r3)->isa->name:"nil", $r4
    cont
    end
    b objc_msgSend_rtp
    comm
    silent
    printf "%c[%s %s]\n", $r3&&((id)$r3)->isa->info&2?'+':'-', $r3?((id)$r3)->isa->name:"nil", $r4
    cont
    end
    
    And you'll get some output like this:
    -[NSTableColumn _bindingAdaptor]
    +[NSBinder binderClassesForObject:]
    +[NSBinder _allBinderClasses]
    +[NSDisplayPatternTitleBinder isUsableWithObject:]
    +[NSBox self]
    
    (courtesy of Rob Mayoff)

  • Archiving a document using keyed archiving (NSCoder->General) (13 October , 2005) [permalink]
    This uses the new Tiger NSDocument load/store. For real code you'll want to handle errors and create an appropriate NSError object. This also saves the document in an XML format.
    - (NSData *) dataOfType: (NSString *) typeName
                      error: (NSError **) error
    {
        *error = nil;
    
        NSMutableData *data = [[NSMutableData alloc] init];
    
        NSKeyedArchiver *archiver;
        archiver = [[NSKeyedArchiver alloc]
                       initForWritingWithMutableData: data];
        [archiver setOutputFormat: NSPropertyListXMLFormat_v1_0];
    
        [archiver encodeObject: stitches  forKey: @"stitches"];
        // and archive other stuff you want
    
        [archiver finishEncoding];
        [archiver release];
    
        return ([data autorelease]);
    
    } // dataOfType
    
    
    - (BOOL) readFromData: (NSData *) data
                  ofType: (NSString *) typeName
                   error: (NSError **) error
    {
        *error = nil;
    
        NSKeyedUnarchiver *archiver;
        archiver = [[NSKeyedUnarchiver alloc]
                       initForReadingWithData: data];
    
        [stitches release];
    
        stitches = [archiver decodeObjectForKey: @"stitches"];
        // decode other stuff of interest
    
        [stitches retain];
    
        return (YES);
    
    } // readFromData

  • Supporting NSKeyedArchiving in your objects (NSCoder->General) (13 October , 2005) [permalink]
    They should conform to the NSCoding protocol.
    - (void) encodeWithCoder: (NSCoder *) coder
    {
        [coder encodeInt: x  forKey: @"x"];
        [coder encodeInt: y  forKey: @"y"];
        [coder encodeObject: color1  forKey: @"color1"];
        [coder encodeObject: color2  forKey: @"color2"];
        [coder encodeInt: direction  forKey: @"direction"];
    
    } // encodeWithCoder
    
    
    - (id) initWithCoder: (NSCoder *) coder
    {
        if (self = [super init]) {
            x = [coder decodeIntForKey: @"x"];
            y = [coder decodeIntForKey: @"y"];
            color1 = [coder decodeObjectForKey: @"color1"];
            color2 = [coder decodeObjectForKey: @"color2"];
            direction = [coder decodeIntForKey: @"direction"];
        }
    
        return (self);
    
    } // initWithCoder

  • Iterating through an NSIndexSet (General->General) (12 October , 2005) [permalink]
    unsigned index;
    for (index = [indexSet firstIndex];
          index != NSNotFound; index = [indexSet indexGreaterThanIndex: index])  {
       ...
    }
    
    (courtesy of mikeash)

  • Putting an image into an attributed string (NSString->General) (29 September, 2005) [permalink]
    You'll need to use a text attachment.
    - (NSAttributedString *) prettyName
    {
        NSTextAttachment *attachment;
        attachment = [[[NSTextAttachment alloc] init] autorelease];
        NSCell *cell = [attachment attachmentCell];
    
        NSImage *icon = [self icon]; // or wherever you are getting your image
        [cell setImage: icon];
    
        NSString *name = [self name];
        NSAttributedString *attrname;
        attrname = [[NSAttributedString alloc] initWithString: name];
    
        NSMutableAttributedString *prettyName;
        prettyName = (id)[NSMutableAttributedString attributedStringWithAttachment:
                                                    attachment]; // cast to quiet compiler warning
        [prettyName appendAttributedString: attrname];
    
        return (prettyName);
    
    } // prettyName
    This puts the image at the front of the string. To put the image in the middle of the string, you'll need to create an attributedstring with attachment, and then append that to your final attributed string.

  • Doing Sheets (NSWindow->General) (19 September, 2005) [permalink]
    To show a sheet in a window, use NSApplication to kick it off:
        [NSApp beginSheet: saveSheet
               modalForWindow: window
               modalDelegate: self
               didEndSelector: @selector(saveSheetDidEnd:returnCode:contextInfo:)
               contextInfo: NULL];
    In the controls in the sheet, use something like
        [NSApp endSheet: saveSheet  returnCode: NSOKButton];
    To invoke the didEndSelector. Inside of that method, you can check the return code and decide what to do:
    - (void) saveSheetDidEnd: (NSWindow *) sheet
                  returnCode: (int) returnCode
                 contextInfo: (void *) contextInfo
    {
        if (returnCode == NSOKButton) {
            // ...
        } else if (returnCode == NSCancelButton) {
            // ...
        } else {
            // ...
        }
    
        [sheet close];
    
    } // saveSheetDidEnd

  • Getting the contents of a TextView as an NSString (NSTextView->NSString) (15 September, 2005) [permalink]
    NSString *commitMessage;
    commitMessage = [[commitTextView textStorage] string];

  • Show NSTextField text in gray if the field is disabled (NSTextView->General) (14 September, 2005) [permalink]
    NSTextField doesn't change its text color if the field is enabled or disabled (?) Even more bizarre, using NSColor's disabledControlTextColor won't draw the text in the disabled color. You need to use the secondarySelectedControlColor, which supposedly is for active controls that don't have focus. Go figure.

    To do it yourself, subclass NSTextField and override setEnabled: to change the color:

    - (void) setEnabled: (BOOL) flag
    {
        [super setEnabled: flag];
    
        if (flag == NO) {
            [self setTextColor: [NSColor secondarySelectedControlColor]];
        } else {
            [self setTextColor: [NSColor controlTextColor]];
        }
    
    } // setEnabled

    This actually kind of a gross workaround for a Cocoa bug - the disabled color is getting made darker rather than lighter. The secondarySelectedControlColor ends up looking disabled by a happy coincidence that it starts out lighter before being darkened. (or something like this. UberDude Dave MacLachlan has done the legwork to figure out the underlying problem.)

  • Monitoring one array from two controllers (Bindings->General) (14 September, 2005) [permalink]
    If you're wanting to use two NSArrayControllers to monitor one NSMutableArray, you'll need to use each of the controller's contentArray binding. Just using the content outlet (or setContent: call), you'll only get arrangedObjects updates from one controller. (thanks to Duncan Wilcox for this one)

  • Replacing NSTextView's contents with an attributed string (NSTextView->General) (12 September, 2005) [permalink]
            [[textView textStorage] setAttributedString: theNewString];

  • Unslecting all segments with radio-mode tracking (NSSegmentedControl->Hacks) (12 September, 2005) [permalink]
    NSSegmentedControl won't let you unselect all segments if there is currently one segment selected (it's perfectly happy with having everything unselected so long as nothing else is selected). This is annoying, so you have to go into the Momentary tracking mode, unselect each of the cells, then go back to the original mode.

    In my NSSegmentedControl category, I have a method to solve this problem:

    @interface NSSegmentedControl (BorkwareAdditions)
    - (void) unselectAllSegments;
    // ... other goodies
    @end // NSSegmentedControl
    
    - (void) unselectAllSegments
    {
        NSSegmentSwitchTracking current;
        current = [self trackingMode];
    
        [self setTrackingMode: NSSegmentSwitchTrackingMomentary];
    
        int i;
        for (i = 0; i < [self segmentCount]; i++) {
            [self setSelected: NO  forSegment: i];
        }
    
        [self setTrackingMode: current];
    
    } // unselectAllSegments

  • Handling KVO with arrays (Bindings->General) (11 September, 2005) [permalink]
    When you insert or remove objects in a KVO compliant manner, your observer is informed of the specifics of the change via the change dictionary:
    - (void) observeValueForKeyPath: (NSString *) keyPath
                           ofObject: (id) object
                             change: (NSDictionary *) change
                            context: (void *) context
    The NSKeyValueChangeKindKey key in the dictionary tells you if the change was an insertion (NSKeyValueMinusSetMutation) or a deletion (NSKeyValueIntersectSetMutation)

    If it is an insertion, the NSKeyValueChangeIndexesKey is an index set that contains the index of the inserted object. You can query the collection for the object at that index to get the new object.

    if it a deletion, the NSKeyValueChangeIndexesKey tells you the index where the object was deleted from, and the NSKeyValueChangeOldKey contains an NSArray of objects which were removed, in case you want to hang on to it, or use it to clean out some of your data structures.

  • Force an NSWindowController's nib to be loaded (NSWindow->General) (10 September, 2005) [permalink]
    The window controller nib doesn't get loaded until the window is manipulated. This can cause confusion if you do any kind of setup before the window is shown. If you call the window method, that will force the nib file to be loaded. Something like this:
    + (BWInspector *) sharedInspector
    {
        static BWInspector *s_inspector;
    
        if (s_inspector == nil) {
            s_inspector = [[BWInspector alloc]
                              initWithWindowNibName: @"BWInspector"];
            assert (s_inspector != nil);
    
            // force loading of nib
            (void) [s_inspector window];
        }
    
        return (s_inspector);
    
    } // sharedInspector

  • Making a panel not eat the key (NSWindow->General) (10 September, 2005) [permalink]
    The default settings for an NSPanel in IB cause the panel to take the main window out of the responder chain, and so commands (like undo) don't propagate to the window the inspector is editing. In IB, make sure the settings "Utility window" and "Non Activating Panel" are selected.

  • Finding the height of the title bar (NSWindow->General) (04 September, 2005) [permalink]
    When you setFrame: for a window, you have to account for the height of the title bar. In the Classic days it was 16 pixels. In Aqua-land, it's currently 22 pixels. But that's not safe to use, so try this instead:
    - (float) titleBarHeight
    {
        NSRect frame = NSMakeRect (0, 0, 100, 100);
    
        NSRect contentRect;
        contentRect = [NSWindow contentRectForFrameRect: frame
                                styleMask: NSTitledWindowMask];
    
        return (frame.size.height - contentRect.size.height);
    
    } // titleBarHeight
    Rainer Brockerhoff points out that this might miss any system-suppled window decorations at the bottom of the window. There aren't any now, but Mac OS X 10.37 Sabertooth might, so you may want to take into account the y positions of the original rectangle and the newly calculated content rect.

  • Resizing a window with animation (NSWindow->General) (04 September, 2005) [permalink]
    Use setFrame:display:animate: to resize a window, and have the window animate between the two sizes. Remember that Cocoa uses a bottom-left origin, which is a pain when dealing with windows. You want the window's top left to be the same between the old and new sizes, so you have to dink with the origin as well as the size:
        float delta = ... how much to make the window bigger or smaller ...;
        NSRect frame = [window frame];
    
        frame.origin.y -= delta;
        frame.size.height += delta;
    
        [window setFrame: frame
                 display: YES
                 animate: YES];
    

  • Resizing a window with animation and cool cross-fade effect with views (NSWindow->General) (04 September, 2005) [permalink]
    NSViewAnimation lets you resize a window and cross-fade some views in one operation. (note I've had problems with the window size getting a couple of pixels off using this. Hopefully either I'm doing something dumb, or Apple fixes a bug). This code resizes the window, and changes the view that lives inside of a box. This is like how the Pages inspector works (except Pages doesn't do the gratuitous animation effect)
        NSRect newWindowFrame = ... the new window size;
    
        NSDictionary *windowResize;
        windowResize = [NSDictionary dictionaryWithObjectsAndKeys:
                                     window, NSViewAnimationTargetKey,
                                     [NSValue valueWithRect: newWindowFrame],
                                     NSViewAnimationEndFrameKey,
                                     nil];
    
        NSDictionary *oldFadeOut = nil;
        if (oldView != nil) {
            oldFadeOut = [NSDictionary dictionaryWithObjectsAndKeys:
                                       oldView, NSViewAnimationTargetKey,
                                       NSViewAnimationFadeOutEffect,
                                       NSViewAnimationEffectKey, nil];
        }
    
        NSDictionary *newFadeIn;
        newFadeIn = [NSDictionary dictionaryWithObjectsAndKeys:
                                      newView, NSViewAnimationTargetKey,
                                  NSViewAnimationFadeInEffect,
                                  NSViewAnimationEffectKey, nil];
    
        NSArray *animations;
        animations = [NSArray arrayWithObjects:
                                  windowResize, newFadeIn, oldFadeOut, nil];
    
        NSViewAnimation *animation;
        animation = [[NSViewAnimation alloc]
                        initWithViewAnimations: animations];
    
        [animation setAnimationBlockingMode: NSAnimationBlocking];
        [animation setDuration: 0.5]; // or however long you want it for
    
        [animation startAnimation]; // because it's blocking, once it returns, we're done
    
        [animation release];

  • Bizarro Error message (Tools->General) (02 September, 2005) [permalink]
    gcc gave me this error:
    cc1obj: error: type '<built-in>' does not have a known size
    without any line number to give a clue what was going on. The error turned out to be having an objective-C method with an argument type of (void), a typo that should have been (void *).

  • Draw a string centered in a rectangle (Graphics->General) (02 September, 2005) [permalink]
        NSString *blah = @"Placeholder Pane";
        NSSize size = [blah sizeWithAttributes: nil];
    
        NSPoint startPoint;
        startPoint.x = bounds.origin.x + bounds.size.width / 2 - size.width / 2;
        startPoint.y = bounds.origin.y + bounds.size.height / 2 - size.height / 2;
    
        [blah drawAtPoint: startPoint
              withAttributes: nil];
    

  • Registering default user defaults (Bindings->General) (02 September, 2005) [permalink]
    Here is one way to register the "factory settings" for your user defaults (preferences / configurations). You will pick up these values automagically via bindings to the Shared Defaults.
    - (void) setDefaultPrefs
    {
        NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
    
        [dictionary setObject: NSLocalizedString(@"BorkDown", nil)
                    forKey: @"menuTitle"];
    
        [dictionary setObject: NSLocalizedString(@"Time has run out.", nil)
                    forKey: @"alertWindowText"];
    
        // and any other preferences you might have
    
        [[NSUserDefaults standardUserDefaults]
            registerDefaults: dictionary];
    
    } // setDefaultPrefs

  • Posing as a class (Hacks->General) (01 September, 2005) [permalink]
    Say you wanted to take a peek at how NSSpellChecker does its thing. You can make a subclass, override methods, log interesting stuff, and then send super. UseposeAsClass: to hook yourself into the matrix during the +load method:
    @interface BorkSpellChecker : NSSpellChecker
    {
    }
    @end // BorkSpellChecker
    
    
    @implementation BorkSpellChecker
    
    + (void) load
    {
        NSLog (@"posing");
        [self poseAsClass: [NSSpellChecker class]];
    
    } // load
    
    
    - (void) ignoreWord: (NSString *) word  inSpellDocumentWithTag: (int) tag
    {
        NSLog (@"ignore word: %@  intag: %d",
               word, tag);
        [super ignoreWord: word
               inSpellDocumentWithTag: tag];
    
    } // ignoreWord

  • Determining the paragraph style at a particular point (NSTextView->General) (29 August , 2005) [permalink]
    - (NSParagraphStyle *) paragraphStyleInTextView: (NSTextView *) textView
                                            atIndex: (int) index
    {
        NSTextStorage *storage = [textView textStorage];
    
        NSDictionary *attributes;
        NSRange effectiveRange;
        attributes = [storage attributesAtIndex: index
                              effectiveRange: &effectiveRange];
    
        NSParagraphStyle *style;
        style = [attributes valueForKey: NSParagraphStyleAttributeName];
    
        return (style);
    
    } // paragraphStyleInTextView

  • Finding the span of a paragraph (NSTextView->General) (29 August , 2005) [permalink]
    The NSString paragraphRangeForRange: method gives you the span of a paragraph. If you're using the text architecture, you need to get the string from the text storage. This chunklet shows the paragraph span for the current selection:
        NSRange selectedRange = [textview selectedRange];
        NSTextStorage *storage = [textview textStorage];
        effectiveRange = [[storage string] paragraphRangeForRange: selectedRange];

  • Adding Growl Notifications (Random->General) (25 August , 2005) [permalink]
    It's pretty easy adding growl notifications to your app. Download the SDK from growl.info. Set up your Xcode project to copy the Growl.framework into your application bundle.

    Pick a class to be the contact point with Growl. Your AppController class is a good place. Import <Growl/Growl.h>

    Set the delegate to the GrowlApplicationBridge:

        [GrowlApplicationBridge setGrowlDelegate: self];
    Doing this will eventually have the registrationDictionaryForGrowl delegate message called. Return a dictionary with two arrays (Which can be the same). These are the names of the alerts you will be posting. These are human-readable, so you'll want to use a localized string (which I've already set in the global variable here:
    - (NSDictionary *) registrationDictionaryForGrowl
    {
        NSArray *notifications;
        notifications = [NSArray arrayWithObject: g_timesUpString];
    
        NSDictionary *dict;
    
        dict = [NSDictionary dictionaryWithObjectsAndKeys:
                                 notifications, GROWL_NOTIFICATIONS_ALL,
                             notifications, GROWL_NOTIFICATIONS_DEFAULT, nil];
    
        return (dict);
    
    } // registrationDictionaryForGrowl
    
    And use this to post a notification:
    [GrowlApplicationBridge notifyWithTitle: @"Woop!  Time has expired!"
                            description: @"You have been waiting for 37 minutes"
                            notificationName: g_timesUpString
                            iconData: nil
                            priority: 0
                            isSticky: NO
                            clickContext: nil];
    
    Consult the SDK documentation for more explanations of the features, but they are pretty self-explanitory.

  • Adding credits to your about box (Xcode->General) (23 August , 2005) [permalink]
    If you have a file called "Credits.html" or "Credits.rtf", the contents of that file will be added to your about box. If your project doesn't have one already, you can use Xcode to add an empty file and put it in your English.lproj folder. Make sure you add it to your project.

  • A Quieter NSLog (General->Hacks) (22 August , 2005) [permalink]
    // NSLog() writes out entirely too much stuff.  Most of the time I'm
    // not interested in the program name, process ID, and current time
    // down to the subsecond level.
    // This takes an NSString with printf-style format, and outputs it.
    // regular old printf can't be used instead because it doesn't
    // support the '%@' format option.
    
    void QuietLog (NSString *format, ...) {
      va_list argList;
      va_start (argList, format);
      NSString *message = [[[NSString alloc] initWithFormat: format
                                                  arguments: argList] autorelease];
      fprintf (stderr, "%s\n", [message UTF8String]);
      va_end  (argList);
    } // QuietLog
    

  • Using an NSWIndowController to load a window (NSWindow->General) (22 August , 2005) [permalink]
    Here's how I like doing things. First make a subclass of NSWindowController:
    @interface BWInspector : NSWindowController
    {
        // ivars, IBOutlets, etc
    }
    
    // IBActions, etc
    
    + (BWInspector *) sharedInspector;
    @end // BWInspector
    
    Then make a nib file with the window, the controls, and other fun stuff you want. This one lives in English.lproj/BWInspector.nib

    Then in that class method load the window:

    + (BWInspector *) sharedInspector
    {
        static BWInspector *g_inspector;
    
        if (g_inspector == nil) {
            g_inspector = [[BWInspector alloc]
                              initWithWindowNibName: @"BWInspector"];
    
            assert (g_inspector != nil); // or other error handling
    
            [g_inspector showWindow: self];
        }
    
        return (g_inspector);
    
    } // sharedInspector
    That will load the nib file, set up the connections and then open the window for display

  • Making localizable strings (NSString->General) (22 August , 2005) [permalink]
    You will need a file named Localizable.strings that lives in your English.lproj directory (or whatever localization directory is appropriate). It has this syntax:
    "BorkDown" = "BorkDown";
    "Start Timer" = "Start Timer";
    "Stop Timer" = "Stop Timer";
    That is, a key followed by a localized value.

    In your code, you can then use NSLocalizedString() or one of its variants:

            [statusItem setTitle: NSLocalizedString(@"BorkDown", nil)];
    The second argument is ignored by the function. Obstensively it is a /* comment */ in the strings file so that you can match the key back to what it is supposed to actually be.

  • Ignoring files (Subversion->General) (19 August , 2005) [permalink]
    I don't want subversion to mess with some files, or to tell me about them when doing an svn status. Add this to your ~/.subversion/config file.
    [miscellany]
    global-ignores = build *.mode* *.pbxuser *~.nib .DS_Store *~
    
    Now it won't bug me about the build directory the -per-user Xcode files, nib backup files, the #$&!! .DS_Store file that the Finder litters everywhere, and also don't bug me about emacs backup files.

    You can search for global-ignores in that file to see some info about the setting. You might want to check out Spring Cleaning with Subversion too.

  • Turning off ZeroLink in all of the project templates (Xcode->General) (18 August , 2005) [permalink]
    I loathe ZeroLink. It causes more problems than it fixes. The Xcode guys must love it dearly. The new .xcconfig files in Xcode 2.1 won't let you turn it off, rendering those files useless to me. The Official Apple suggestion is to edit all of your project templates (?). Here is a quick script that'll churn through all of the project templates (and also your own projects) and turn off ZeroLink.
    % cd '/Library/Application Support/Apple/Developer Tools/Project Templates'
    % find . -name "*.pbxproj" -exec perl -pi -e "s/ZERO_LINK = YES/ZERO_LINK = NO/g" {} \; -print
    

  • Iterating attributes in an attributed string (NSString->General) (27 July , 2005) [permalink]
    This prints out each of the attribute runs from an attributed string:
    NSAttributedString *string = ...;
    
    NSRange totalRange = NSMakeRange (0, string.length);
    [string enumerateAttributesInRange: totalRange
            options: 0
            usingBlock: ^(NSDictionary *attributes, NSRange range, BOOL *stop) {
    
                NSLog (@"range: %@  attributes: %@",
                       NSStringFromRange(range), attributes);
        }];
    
    
    
    and if you're in 10.5 or earlier:
    - (void) iterateAttributesForString: (NSAttributedString *) string
    {
        NSDictionary *attributeDict;
        NSRange effectiveRange = { 0, 0 };
    
        do {
            NSRange range;
            range = NSMakeRange (NSMaxRange(effectiveRange),
                                 [string length] - NSMaxRange(effectiveRange));
    
            attributeDict = [string attributesAtIndex: range.location
                                    longestEffectiveRange: &effectiveRange
                                    inRange: range];
    
            NSLog (@"Range: %@  Attributes: %@",
                   NSStringFromRange(effectiveRange), attributeDict);
    
        } while (NSMaxRange(effectiveRange) < [string length]);
    
    } // iterateAttributesForString

  • Resizing Windows in IB (Tools->General) (14 July , 2005) [permalink]
    Resizing complex windows in IB can be a pain because the contents don't reflow when you change the window size.

    In Interface Builder 2: If you hold down the control key while resizing, though, the contents obey their spring configurations and will resize accordingly. Makes the process a whole lot easier.

    In Interface Builder 3: If you hold down command while resizing, the contents obey their spring configurations and will resize accordingly. (This avoids the annoying process of resizing each widget within the windows afterwards.) Holding option while resizing will display the pixel values of the padding. Holding command-option while dragging displays both.

    (muchos thankos to Quinn Taylor at the BYU CocoaHeads for the IB3 update)

  • View with bindings (Bindings->General) (13 July , 2005) [permalink]
    ThumbBorker has a custom view class that updates a selection rectangle when the user finished dragging the mouse. It uses setValue:forKeyPath: to stick the value back into the bound object.

    The bindings and path are ivars:

         id selectionRectBinding;
         NSString *selectionRectKeyPath;
    In bind:toObject:withKeyPath:options: hang on to the binding object and the key path and set up observing:
             // hold on to the binding info
             selectionRectBinding = observableObject;
             selectionRectKeyPath = [observableKeyPath copy];
    
             // connect KVO
             [valuePathBinding addObserver: self
                               forKeyPath: selectionRectKeyPath
                               options: nil
                               context: NULL];
    
             // new binding, needs to redraw
             [self setNeedsDisplay: YES];
    And in the mouseUp: handler, set the value back into the bound object:
         // figure out the selection rectangle
         NSRect selectionRect = [self normalizedSelectionRect];
    
         // wrap in a value and tell the bound object the new value
    
         NSValue *value;
         value = [NSValue valueWithRect: selectionRect];
    
         [selectionRectBinding setValue: value
                               forKeyPath: selectionRectKeyPath];

  • Setting computed default value for a managed object (Core Data->General) (13 July , 2005) [permalink]
    Make a subclass of NSManagedObject and override awakeFromInsert:
    - (void) awakeFromInsert
    {
        [super awakeFromInsert];
    
        NSDate *date = [NSDate date];
    
        [self setValue: date  forKey: @"when"];
    
    } // awakeFromInsert

  • Changing the "Not Applicable" text in tableviews (Bindings->General) (11 July , 2005) [permalink]
    Sometimes you want to bind a tableview column to objects that might not support that particular binding (like having an uber-overview tableview for core data entities that don't all share the same attributes). If your column has a numeric formatter, IB won't let you specify a string for the "not applicable" value, so you end up with a really ugly tableview covered in "Not Applicable"s

    Put this in a convenient place:

    + (void) initialize
    {
        [NSTextFieldCell setDefaultPlaceholder: @""
                                   forMarker: NSNotApplicableMarker
                                 withBinding: NSValueBinding];
    
    } // initialize

  • NSSearchField filtering for an NSArrayController (Bindings->General) (10 July , 2005) [permalink]
    In Tigger, NSSearchField can now automagically filter an array via IB magic.

    In Interface Builder, drag over the NSSearchField, and bind the predicate like this:

    • Bind To: your array controller
    • Controller Key: filterPredicate
    • Predicate Format: what contains[c] $value (assuming the attribute you're filtering is called what)
    If you're wanting to be able to filter on multiple attributes, make additional predicate bindings. Doing the CoreData option-drag of an entity into IB is really handy - take a peek at how it configures the search field for filtering multiple columns.

  • Making a tag / branch (Subversion->General) (10 July , 2005) [permalink]
    This will make a tag called "stable-1" of the current trunk revision:
    % svn copy file:///usr/local/svnroot/HackDie/trunk 
                file:///usr/local/svnroot/HackDie/tags/stable-1 
                -m "tag for HackDie internal stable release #1"
    

  • Custom Accessor Methods (scalar) (Core Data->General) (09 July , 2005) [permalink]
    Say there's a float ivar called radius
    - (float) radius
    {
        [self willAccessValueForKey: @"radius"];
        float f = radius;
        [self didAccessvalueForKey: @"radius"];
    
       return (f);
    
    } // radius
    
    
    - (void) setRadius: (float) newRadius
    {
        [self willChangeValueForKey: @"radius"];
        radius = newRadius;
        [self didChangeValueForKey: @"radius"];
    
    } // setRadius
    

  • Custom accessor methods (objects) (Core Data->General) (09 July , 2005) [permalink]
    Wrap the methods with will/did Access/Change ValueForKey:, and also use KVC to set primitive values:
    - (NSString *) name
    {
        [self willAccessValueForKey: @"name"];
        NSString *string = [self primitiveValueForKey: @"name"];
        [self didAccessValueForKey: @"name"];
    } // name
    
    - (void) setName: (NSString *) x
    {
        [self willChangeValueForKey: @"name"];
        [self setPrimitiveValue: x  forKey: @"name"];
        [self didChangeValueForKey: @"name"];
    } // setName
    

  • Inserting an object (Core Data->General) (09 July , 2005) [permalink]
    Inserting a new object into a managed object context is a multi-stage process. This assumes that self has methods to get the managed object context and managed object model (Apple's CoreData Application template does)

    Thanks to Evan Moseman who pointed me at the new easy way to do it:

            NSManagedObjectContext *moc = [self managedObjectContext];
    	NSManagedObject *obj = [NSEntityDescription 
    		insertNewObjectForEntityForName :@"Condition" 
    		inManagedObjectContext: context];
    
    And the older, more manual way if you need some more control over the process:
        NSManagedObjectContext *moc = [self managedObjectContext];
        NSManagedObjectModel *mom = [self managedObjectModel];
    
        NSEntityDescription *entity;
        entity = [[mom entitiesByName] objectForKey: @"Condition"];
    
        NSString *className;
        className = [entity managedObjectClassName];
    
        NSManagedObject *obj;
        obj = [[NSClassFromString(className) alloc]
                  initWithEntity: entity
                  insertIntoManagedObjectContext: moc];
    
        [obj autorelease];
    
        [obj setValue: @"nook"  forKey: @"name"];
        [obj setValue: [NSNumber numberWithInt: 23]  forKey: @"ranking"];
    

  • Manipulating a to-many relationship (Core Data->General) (09 July , 2005) [permalink]
    Use mutableSetValueForKey: This returns a proxy that mutates the relationship and does KVO notifications. Think of the name as "[NS]MutableSet" "valueForKey" rather than "mutableSetValue" "forKey", because it returns a mutable set that you manipulate
    NSMutableSet *employees;
    employees = [department mutableSetValueForKey: @"employees"];
    [employees addObject: newEmployee];
    [employees removeObject: sackedEmployee];
    

  • Manually sorting results in a fetch request (Core Data->General) (09 July , 2005) [permalink]
    I haven't figured out how to get the Xcode fetched query editor to sort. In the mean time, here's how to do it in code:
        NSSortDescriptor *sorter;
        sorter = [[NSSortDescriptor alloc]
                     initWithKey: @"when"
                     ascending: YES];
    
        [fetchRequest setSortDescriptors:
                   [NSArray arrayWithObject: sortDescriptor]];
    

  • Sorting results (Core Data->General) (09 July , 2005) [permalink]
    Want data to be sorted in tableviews and whatnot? You can set the "sortDescriptors" binding on an array controller. Write a method that returns the sort descriptors you want:
    - (void) setWhenSortDescriptors: (NSArray *) descriptors
    {
    } // setWhenSortDescriptors
    
    
    - (NSArray *) whenSortDescriptors
    {
        NSSortDescriptor *sorter;
        sorter = [[[NSSortDescriptor alloc]
                      initWithKey: @"when"
                      ascending: NO] autorelease];
    
        return ([NSArray arrayWithObject: sorter]);
    
    } // whenSortDescriptors
    
    This is for a 'permanent' sorting, not allowing the user to change the sorting. Also, new/changed objects added to the collection don't appear to be placed in sorted order.

  • Storing Images into the data store (Core Data->General) (09 July , 2005) [permalink]
    So ya want to store an image into the data store. mmalc says

    Don't use the XML store, but instead use the SQLite store

    If an entity has a large data blob as an attribute, you should make a separate entity for that attribute.

    e.g. a Person has a 'photo' attribute. Create a Photo entity with a single attribute (the data) and a relationship back to the person (if it makes sense, usually it does), and a relationship from the Person to the Photo entity.

    This means that the photo data will only be loaded from the persistent store if you actually use it.

    (markd: this also has the nice side effect of letting the db put all the blob data elsewhere, rather than in with the other data, giving you better locality of reference to your Person data without slogging through all the Photo jazz if you don't need it)

  • Blanket Disabling of ZeroLink (Xcode->Hacks) (29 June , 2005) [permalink]
    (see also ZeroLink Must Die.

    This find will grovel around project files and turn off ZeroLink. You can start at the path here to turn it off in all of your Xcode templates, and you can also point the find at your own XCode projects. Make backups first if you're feeling squeamish or your stuff isn't under version control.

    % cd '/Library/Application Support/Apple/Developer Tools/Project Templates'
    % find . -name "*.pbxproj" -exec perl -pi -e "s/ZERO_LINK = YES/ZERO_LINK = NO/g" {} \; -print
    

  • Showing all files that changed at a particular revision (Subversion->General) (23 June , 2005) [permalink]
    If you're inside of a working copy, you can do:
    % svn log -v -r 373
    ------------------------------------------------------------------------
    r373 | markd | 2005-06-22 16:05:38 -0400 (Wed, 22 Jun 2005) | 1 line
    Changed paths:
       A /xyz/trunk/docs/bugreports/4158233-nsbrowser
       A /xyz/trunk/docs/bugreports/4158233-nsbrowser/browser-rows.png
       A /xyz/trunk/docs/bugreports/4158233-nsbrowser/browserdraw.tar.gz
       A /xyz/trunk/docs/bugreports/4158233-nsbrowser/bug.txt
    
    initial revision
    ------------------------------------------------------------------------
    
    and you can look repository-wide too: % svn log -v -r 373 file:///usr/local/svnroot/

  • Access environment variables from Cocoa (Random->General) (13 June , 2005) [permalink]
    Check out NSProcessInfo's environment method

  • Setting environment variables for the gui login session (Random->General) (13 June , 2005) [permalink]
    For environment variables you want set for the user's GUI login session, make a plist called ~/.MacOSX/environment.plist. Make the root a Dictionary, and add the key/value pairs (all strings) to it. Don't forget to logout and back in.

  • Apple-Generic Versioning (Xcode->General) (11 April , 2005) [permalink]
    You can use agvtool do to apple-style generic versioning, which has two version numbers - one's a float that's monotonically increasing, and the other is a "marketing" version, that can be things like "1.0.4b34". Courtesy of Chris Hanson from a mailing list posting:

    Set your Versioning System (VERSIONING_SYSTEM) to "apple-generic".

    Set your Current Project Version (CURRENT_PROJECT_VERSION) to some floating point value that you'll increment every build. You could just start at 1, unless you already have builds out there with other numbers.

    This will generate and build a source file automatically that defines two globals whenever you build your project. One is a double corresponding to CURRENT_PROJECT_VERSION, the other is a string. The file is a derived source file; it won't be added to your project, but it will be built with it.

    If you're building a framework, there are other build settings you'll probably want to set as well, such as Current Version (DYLIB_CURRENT_VERSION), Compatibility Version (DYLIB_COMPATIBILITY_VERSION), and VERSION_INFO_PREFIX.

    To update the version number, you can use agvtool next-version or agvtool new-version.

  • Make Mail.app display plain text messages (Random->Random) (07 April , 2005) [permalink]
    Many HTML emails I receive get rendered in Mail.app in tiny, tiny point sizes. To have Mail.app prefer to display plain text instead, quit Mail.app and run this:

    % defaults write com.apple.mail PreferPlainText -bool TRUE

  • Using tar to copy across the network (Unix->General) (03 April , 2005) [permalink]
    % tar cf - ./stuff | ssh theOtherMachine "tar xf -"

  • Restrict editing to the region (emacs->General) (31 March , 2005) [permalink]
    M-x narrow-to-region

    Hides everything not in the current region.

  • Unnarrowing the region (emacs->General) (31 March , 2005) [permalink]
    M-x widen

  • Open path sheet in the Finder (General->General) (28 March , 2005) [permalink]
    Open a Finder window, then type command-shift-g. Works in standard file dialogs too.

  • Add new directory directly to repository (Subversion->General) (18 March , 2005) [permalink]
    % svn mkdir -m "initial revision" file:///usr/local/svnroot/MilleBorks

  • Adding new project to repository (1 project : 1 repository) (Subversion->General) (18 March , 2005) [permalink]
    The Subversion folks recommend that project have a branches, tag, and trunk directory, to make doing things like branches and tags easier. Importing this way will mean your repository will only have this one project.
    % mkdir DungeonBorkventure
    % cd DungeonBorkventure
    % mkdir branches tags trunk
    # put source files into trunk
    % svn import . file:///usr/local/svnroot -m "initial checkin"
    % cd ..
    % rm -rf DungeonBorkventure  # or move it aside
    % svn checkout file:///usr/local/svnroot/trunk DungeonBorkventure
    % cd DungeonBorkventure
    # and get to work

  • Adding new project to repository (multiple projects : 1 repository) (Subversion->General) (18 March , 2005) [permalink]
    To have multiple projects in one repository, you have to create directories in the repository first to hold the project, then import the code. Here is importing two projects, MilleBorks and DungeonBorkventure

    First, make the directories in the repository:

    % svn mkdir -m "initial revision" file:///usr/local/svnroot/DungeonBorkventure
    % svn mkdir -m "initial revision" file:///usr/local/svnroot/MilleBorks
    Then import the different code bases:
    % cd /path/to/DungeonBorkventure
    % svn import -m "initial revision" . file:///usr/local/svnroot/DungeonBorkventure
    % cd /path/to/MilleBorks
    % svn import -m "initial revision" . file:///usr/local/svnroot/MilleBorks
    Then checkout working copies of the projects:
    % cd /work/and/play/area
    % svn checkout file:///usr/local/svnroot/MilleBorks/trunk MilleBorks
    % svn checkout file:///usr/local/svnroot/DungeonBorkventure/trunk DungeonBorkventure
    

  • Making a new FSFS repository (Subversion->General) (18 March , 2005) [permalink]
    % svnadmin create --fs-type fsfs /usr/local/svnroot/

  • Seeing what files will come down in the next update (Subversion->General) (18 March , 2005) [permalink]
    To see if folks have committed changes that'll get brought down in the next update.

    % svn status --show-updates

    You can specify files and directories of interest.

  • Merging a Branch with new directories in CVS (CVS->General) (16 March , 2005) [permalink]
    When merging a branch back into the trunk (using the update command) be sure to use the -d option. Otherwise CVS will just ignore any directories added in the branch.

    % cvs update -Ad  #switch to the trunk (if you haven't already)
    % cvs update -d -j branch_name
    [resolve conflicts]
    % cvs commit -m "whatever"

    (Courtesy of Jeremy Stein)

  • Using awk to print fields (Unix->General) (14 March , 2005) [permalink]
    Here's a way to have awk print all fields (separated by spaces) from each line, except for fields number 1 and 9 (starting with a count of 1):
    % awk '{ for (f=1; f <= NF; f++) { if (f != 1 && f != 9) printf("%s ", $f);} printf("
    ");}' < ook.txt
    Or you can put this at the end of a pipeline instead of directing a text file into the command. (courtesy of DougEDoug)

  • Loading a bundle into a running program (gdb->Hacks) (28 February , 2005) [permalink]
    Sometimes it's handy to load a bundle into a running app to do some poseAsClass: for doing some debugging or reverse engineering. Make a Cocoa bundle which has the code you want to load, then do:
    (gdb) call (id) objc_getClass("NSBundle")
    $1 = (struct objc_object *) 0xa0a051d8
    
    gdb) call (id)[$1 bundleWithPath:@"/blah/blah/PoseAsClassBundle.bundle"]
    $2 = (struct objc_object *) 0x51467e0
    
    (gdb) call (BOOL)[$2 load]
    Reading symbols for shared libraries . done

  • Enabling "control reaches end of non-void function" (Xcode->General) (28 February , 2005) [permalink]
    One nice gcc warning that's not enabled by default is one that complains if you exit from a function (by falling off the end) without returning anything. This is an easy error to make, and can be hard to track down (especially if you do it in an objective-C init method). To enable this warning, add "-Wreturn-type" to the "Other C Flags" setting in your favorite build style.

  • Getting the current user's name (Random->General) (26 February , 2005) [permalink]
    NSUserName() or NSFullUserName().

    Thanks to Peter Hosey for letting us know about a better API for getting these.

  • Responding to modifier keys only (NSView->General) (24 February , 2005) [permalink]
    NSView's keyDown: and keyUp: don't fire when just a modifier key goes down. If you do want to react to this, you'll need to override flagsChanged: (NSEvent *) eventand look at the event there. (flagsChanged: comes from NSResponder, so any responder in the responder chain can react to it)

  • Observing using KVO (Bindings->General) (24 February , 2005) [permalink]
    Register an observer with something like:
        [searchArrayController addObserver: self
                               forKeyPath: @"selectionIndexes"
                               options: NSKeyValueObservingOptionNew
                               context: NULL];
    This makes self an observer of the searchArrayController. We'll get notified when the selectionIndexes value changes, and we'll be notified with the new value.

    When the notification happens, this method (invoked against the self used earlier) is invoked:

    - (void) observeValueForKeyPath: (NSString *) keyPath
                           ofObject: (id) object
                             change: (NSDictionary *) change
                            context: (void *) context
    {
    } // observeValueForKeyPath
    
    and you can poke around the arguments to see wha'happened.

  • Fixing Bindings-related memory leak (Bindings->Hacks) (24 February , 2005) [permalink]
    If you have bindings hooked up to File's Owner in some circumstances (like with an NSWindowController-based nib file), a retain cycle is created, and so the window controller will never get released (having an extra retain for each binding to File's Owner). An easy way to work around this is to;
    • Add an NSObjectController (I call it "Fake FIle's Owner") to the nib file and the window controller class.
    • Point the bindings to the controller rather than file's owner
    • Hook up the window controller's outlet to point to the object controller
    • [fakeFileOwner setContent: self]
    Then again, this all might be Wrong. jkp_ in #macdev points out that the setContent:self will retain self twice more, with no release in sight. The only wayd that would really work is if you provided a subclass of NSObjectController that released after it setContent: and also in _startObservingObject: That might be the cleanest solution - provide a custom proxy object that doesnt retain the filesOwner and bind to that....same thing, only you have to do the overrides. So this one's in limbo(e) for now. wheeee! He's come up with a hack to work around things:
    - (oneway void) release;
    {
        // special case when count is 3, we are being retained twice by the object controller...
        if ( [self retainCount] == 3 )
        {
            [super release];
            [filesOwnerProxy setContent:nil];
            return;
        }
        
        [super release];
    }

  • Reacting to TableView selection changes when using bindings (Bindings->NSTableView) (24 February , 2005) [permalink]
    You're using bindings to handle the tableview, but now you have some code that needs to do something when the selection changes (in my case I was disabling a sheet's OK button if the selection in two tableviews was the same). The way to track that change is to add yourself as an observer of the array controller that's driving the tableview, and then do the work in the observeValueForKeyPath: method. Register your observer like this:
        [searchArrayController addObserver: self
                               forKeyPath: @"selectionIndexes"
                               options: NSKeyValueObservingOptionNew
                               context: NULL];
    So now self's observeValue method will get invoked when selectionIndexes changes in the array controller.

  • Performing relative (grab-hand) scrolling (NSView->General) (23 February , 2005) [permalink]
    Grab-hand scrolling is a handy feature in several apps. It's nice being able to scroll around a large document diagonally, fer instance. Here's one way to do it (assuming you have a standard NSScrollView -> NSClipView -> YourView setup)

    @interface Blah : NSView
    {
        NSPoint grabOrigin;
        NSPoint scrollOrigin;
    }
    @end // Blah
    
    ...
    
    @implementation Blah
    
    ...
    
    - (void) mouseDown: (NSEvent *) event
    {
        // deal in window coordinates.  there is a scrolling problem
        // if using view coordinates because view coordinates
        // can get transformed
        grabOrigin = [event locationInWindow];
    
        NSClipView *contentView;
        contentView = (NSClipView*)[layerView superview];
    
        scrollOrigin = [contentView bounds].origin;
    
    } // mouseDown
    
    
    - (void) mouseDragged: (NSEvent *) event
    {
        NSPoint mousePoint;
        mousePoint = [event locationInWindow];
    
        float deltaX, deltaY;
        deltaX = grabOrigin.x - mousePoint.x;
        deltaY = mousePoint.y - grabOrigin.y;
    
        NSPoint newOrigin;
        newOrigin = NSMakePoint (scrollOrigin.x + deltaX,
                                 scrollOrigin.y + deltaY);
    
        [layerView scrollPoint: newOrigin];
    
    } // mouseDragged
    ...
    
    @end // Blah
    
    You can be fancy and check for the option key by look at [event modifierFlags] and looking for NSAlternateKeyMask, and also use the NSCursor open/closedHandCursor.

  • Reacting to the Escape key (NSView->General) (21 February , 2005) [permalink]
    There's no predefined constant for the Escape key. Luckily the escape key predates every personal computer, and so it has a pretty reliable character value that's generated: 27:
    - (void) keyDown: (NSEvent *) event
    {
        NSString *chars = [event characters];
        unichar character = [chars characterAtIndex: 0];
    
        if (character == 27) {
            NSLog (@"ESCAPE!");
        }
    } // keyDown

  • Reacting to the delete key (NSView->General) (21 February , 2005) [permalink]
    Look for NSDeleteCharacter in the event's character string:
    - (void) keyDown: (NSEvent *) event
    {
        NSString *chars = [event characters];
        unichar character = [chars characterAtIndex: 0];
    
        if (character == NSDeleteCharacter) {
            NSLog (@"Delete!");
        }
    } // keyDown

  • Minimal KVC accessors for arrays (Bindings->General) (21 February , 2005) [permalink]
    For an attribute named "layers", here are the KVC accessors to write to let observers react to object addition and removal:
    - (NSArray *) layers
    {
        return (layers);
    } // layers
    
    
    - (void) insertObject: (id) obj
          inLayersAtIndex: (unsigned) index
    {
        [layers insertObject: obj  atIndex: index];
    } // insertObjectInLayers
    
    
    - (void) removeObjectFromLayersAtIndex: (unsigned) index
    {
        [layers removeObjectAtIndex: index];
    } // removeObjectFromLayersAtIndex

  • Discovering when exiting a sub event loop (General->General) (18 February , 2005) [permalink]
    [self performSelector: @selector(whatever) withObject: nil afterDelay: 0];

    The selector gets posted after a sub event loop finishes. You can use this for finding out when a live slider is done being manipulated, for instance

  • Using KVO for whole-object observation (Bindings->General) (18 February , 2005) [permalink]
    I've got an object that has a bunch of individual attributes that are controlled by an inspector, and another object (a view that holds that object) which needs to redraw when something changes in the object, but it doesn't care which individual attribute it is. Rather than having the view observe each of the individual attributes, KVO provides a way to automatically trigger another observation when any dependent attribute changes.

    First, in the +initialize for the class that's going to be observed:

    + (void) initialize
    {
        NSArray *keys;
        keys = [NSArray arrayWithObjects: @"showMajorLines", @"minorWeight",
                        @"minorColor", @"minorWeightIndex", @"minorColorIndex",
                        @"majorWeightIndex", @"majorColorIndex", nil];
    
        [BWGridAttributes
            setKeys: keys
            triggerChangeNotificationsForDependentKey: @"gridAttributeChange"];
    
    } // initialize
    So now when "showMajorLines" changes, "gridAttributeChange" will also be observed. KVO requires there actually must exist a gridAttributeChange method (or ivar I presume) before it'll do the notification to observing objects, so there needs to be a do-nothing method:
    - (BOOL) gridAttributeChange
    {
        return (YES);
    } // gridAttributeChange
    So now the view can do this:
    - (void) setGridAttributes: (BWGridAttributes *) a
    {
        [attributes removeObserver: self
                    forKeyPath: @"gridAttributeChange"];
    
        [a retain];
        [attributes release];
        attributes = a;
    
        [a addObserver: self
           forKeyPath: @"gridAttributeChange"
            options: NSKeyValueObservingOptionNew
            context: NULL];
    
    } // setGridAttributes
    And will get updated whenever an individual attribute changes.

  • Adding your own objects to the responder chain (NSObject->General) (09 February , 2005) [permalink]
    For I project I was working on, I needed the editing tools (for a graphical editor) to be in the responder chain so they could react to menu items. Doing this was surprisingly easy.

    First step was to make the tools inherit from NSResponder:

    @interface BWTool : NSResponder
    {
        // blah
    }
    // ... more blah
    @end // BWTool
    Then, in the view class where the tool gets set, put the tool in the responder chain by setting its next responder to be the view's current next responder. If a different tool gets set, take the current tool's next responder and give it to the new tool. Otherwise the view gets its original next responder back:
    - (void) setTool: (BWTool *) newTool
    {
        NSResponder *nextResponder;
    
        // this is the next element in the chain
    
        if (currentTool != nil) {
            nextResponder = [currentTool nextResponder];
        } else {
            nextResponder = [self nextResponder];
        }
    
        // decide who gets to point to the next responder
    
        if (newTool != nil) {
            // stick the tool into the chain
            [self setNextResponder: newTool];
            [newTool setNextResponder: nextResponder];
    
        } else {
            // cut the tool out of the chain (if there was one)
            [self setNextResponder: nextResponder];
        }
    
        [newTool retain];
        [currentTool release];
    
        currentTool = newTool;
    
    } // setDrawTool
    And now tools can have action methods, and menu items that enable and disable appropriately.

  • Disabling "Return moves editing to next cell" in TableView (NSTableView->General) (04 February , 2005) [permalink]
    When you edit cells in a tableview, pressing return, tab, or shift-tab will end the current editing (which is good), and starts editing the next cell. But of times you don't want that to happen - the user wants to edit an attribute of a given row, but it doesn't ever want to do batch changes to everything.

    To make editing end, you need to subclass NSTableView and add code to catch the textDidEndEditing delegate notification, massage the text movement value to be something other than the return and tab text movement, and then let NSTableView handle things.

    // make return and tab only end editing, and not cause other cells to edit
    
    - (void) textDidEndEditing: (NSNotification *) notification
    {
        NSDictionary *userInfo = [notification userInfo];
    
        int textMovement = [[userInfo valueForKey:@"NSTextMovement"] intValue];
    
        if (textMovement == NSReturnTextMovement
            || textMovement == NSTabTextMovement
            || textMovement == NSBacktabTextMovement) {
    
            NSMutableDictionary *newInfo;
            newInfo = [NSMutableDictionary dictionaryWithDictionary: userInfo];
    
            [newInfo setObject: [NSNumber numberWithInt: NSIllegalTextMovement]
                     forKey: @"NSTextMovement"];
    
            notification =
                [NSNotification notificationWithName: [notification name]
                                           object: [notification object]
                                           userInfo: newInfo];
    
        }
    
        [super textDidEndEditing: notification];
        [[self window] makeFirstResponder:self];
    
    } // textDidEndEditing
    (Thanks to Steven Jacowski for a tweak that ends editing on clicks on different cells)

  • Making a table view a drag source (NSTableView->General) (30 January , 2005) [permalink]
    If you want to make your NSTableView a source for a drag and drop operation, you need to implement
    - (BOOL) tableView: (NSTableView *) view
             writeRows: (NSArray *) rows
          toPasteboard: (NSPasteboard *) pboard
    
    in your table view data source (and don't forget to hook up the datasource if you use bindings to populate the tableview)

  • Table View drag destination on or between rows (NSTableView->General) (30 January , 2005) [permalink]
    When your NSTableView is a drag destination, you may want to support both dragging onto existing objects (to replace them, or augment them with some new attribute the user is dragging over) and support dragging between existing objects (to insert a new one in between. To get this behavior, you need to use NSTableView's -setDropRow:dropOperation:, like so:
    - (NSDragOperation) tableView: (NSTableView *) view
                     validateDrop: (id ) info
                      proposedRow: (int) row
            proposedDropOperation: (NSTableViewDropOperation) op
    {
        // have the table highlight on-row / between-row correctly
        [view setDropRow: row
              dropOperation: op];
    
        // or use whatever drag operation is appropriate
        NSDragOperation dragOp = NSDragOperationCopy;
    
        return (dragOp);
    
    } // validateDrop
    and in the acceptDrop method, look at the operation:
    - (BOOL) tableView: (NSTableView *) view
            acceptDrop: (id ) info
                   row: (int) row
         dropOperation: (NSTableViewDropOperation) op
    {
        if (op == NSTableViewDropOn) {
            // replace existing
    
        } else if (op == NSTableViewDropAbove) {
            // add new
    
        } else {
            NSLog (@"unexpected operation (%d) in %s",
                   op, __FUNCTION__);
        }
    
        // documentation doesn't actually say what this signifies
        return (YES);
    
    } // acceptDrop

  • Decoding one class as another (NSCoder->General) (28 January , 2005) [permalink]
    If you change the name of a class, and then try to use NSUnarchiver to expand an archived stream, you'll get an error like this (in this case "BWRawPath" was renamed to "BWSymbol"):

    StitchEdit[3522] *** class error for 'BWRawPath': class not loaded

    In a convenient place (like in the +load method of your class), use NSUnarchiver's decodeClassName:asClassName:

    @implementation BWSymbol
    
    + (void) load
    {
        [NSUnarchiver decodeClassName: @"BWRawPath"
                      asClassName: @"BWSymbol"];
     
        // No need to [super load] - the superclass +load has already
        // been invoked automatically by the runtime.
    
    } // load
    Note that this won't help you if you're wanting to rename something that was added via encodeValueOfObjCType:. You'll have to write some code to unarchive your data using the old @encode(oldName) and then re-archive it as @encode(newName)

    (Thanks to Greg Miller for spotting an error in this quickie)

  • Using a custom title for NSWindowController windows (NSDocument->NSWindow) (26 January , 2005) [permalink]
    When using utility windows in a document-based app, NSWindowController is handy for handling a lot of the grungy details. When using a shared window (like an inspector window), you want its title to reflect that of the document. Override windowTitleForDocumentDisplayName to set the title. In this case, it becomes of the form "Overview of Untitled 2":
    - (NSString *) windowTitleForDocumentDisplayName: (NSString *) displayName
    {
        NSString *string;
        string = [NSString stringWithFormat: @"Overview of %@", displayName];
    
        return (string);
    
    } // windowTitleForDocumentDisplayName

  • Window Position Autosave for NSWindowController-owned inspectors (NSDocument->NSWindow) (26 January , 2005) [permalink]
    It's nice to autosave the position of inspector windows so that they come backup where the user put them. Unfortunately, NSWindowController wipes out the autosave name that's set in Interface Builder. You have to set it in code in your window controller subclass. The windowDidLoad method (which is used instead of awakeFromNib) is a handy place:
    - (void) windowDidLoad
    {
        [super windowDidLoad];
    
        [self setShouldCascadeWindows: NO];
        [self setWindowFrameAutosaveName: @"pannerWindow"];
    
        // and any other windowDidLoad work to be done
    } // windowDidLoad
    

  • Hooking up a search box to your array controller (Bindings->General) (26 January , 2005) [permalink]
    Tiger supposedly does this for us. If you're having to support Panther as well, here's a way to have a search box filter the contents managed by an NSArrayController.

    In the header file

    #import <Cocoa/Cocoa.h>
    
    @interface BWSearchArrayController : NSArrayController
    {
        NSString *searchString;
    }
    
    - (IBAction) search: (id) sender;
    
    @end // BWSearchArrayController
    and then in the implementation:
    // returns an array containing the content of the objects arranged
    // with the user's critera entered into the search box thingie
    
    - (NSArray *) arrangeObjects: (NSArray *) objects
    {
        // result of the filtering
        NSArray *returnObjects = objects;
    
        // if there is a search string, use it to compare with the
        // search field string
    
        if (searchString != nil) {
    
            // where to store the filtered
            NSMutableArray *filteredObjects;
            filteredObjects = [NSMutableArray arrayWithCapacity: [objects count]];
    
            // walk the enumerator
            NSEnumerator *enumerator = [objects objectEnumerator];
    
            id item; // actully BWFileEntries
            while (item = [enumerator nextObject]) {
    
                // get the filename from the entry
                NSString *filename;
                filename = [item valueForKeyPath: @"fileName"];
    
                // see if the file name matches the search string
                NSRange range;
                range = [filename rangeOfString: searchString
                                  options: NSCaseInsensitiveSearch];
    
                // found the search string in the file name, add it to
                // the result set
                if (range.location != NSNotFound) {
                    [filteredObjects addObject: item];
                }
            }
    
            returnObjects = filteredObjects;
        }
    
        // have the superclass arrange them too, to pick up NSTableView sorting
        return ([super arrangeObjects:returnObjects]);
    
    } // arrangeObjects
    and then to set the search string:
    - (void) setSearchString: (NSString *) string
    {
        [searchString release];
    
        if ([string length] == 0) {
            searchString = nil;
        } else {
            searchString = [string copy];
        }
    
    } // setSearchString
    
    
    - (void) search: (id) sender
    {
        [self setSearchString: [sender stringValue]];
        [self rearrangeObjects];
    
    } // search
    

  • Turning a string into a path (Graphics->NSString) (23 January , 2005) [permalink]
    - (NSBezierPath *) makePathFromString: (NSString *) string
                                  forFont: (NSFont *) font
    {
        NSTextView *textview;
        textview = [[NSTextView alloc] init];
    
        [textview setString: string];
        [textview setFont: font];
    
        NSLayoutManager *layoutManager;
        layoutManager = [textview layoutManager];
    
        NSRange range;
        range = [layoutManager glyphRangeForCharacterRange:
                                   NSMakeRange (0, [string length])
                               actualCharacterRange: NULL];
        NSGlyph *glyphs;
        glyphs = (NSGlyph *) malloc (sizeof(NSGlyph)
                                     * (range.length * 2));
        [layoutManager getGlyphs: glyphs  range: range];
    
        NSBezierPath *path;
        path = [NSBezierPath bezierPath];
    
        [path moveToPoint: NSMakePoint (20.0, 20.0)];
        [path appendBezierPathWithGlyphs: glyphs
              count: range.length  inFont: font];
    
        free (glyphs);
        [textview release];
    
        return (path);
    
    } // makePathFromString
    

  • Outlining every view (NSView->Debugging) (22 January , 2005) [permalink]
    You can set the NSShowAllViews default value to have every view outlined. Nested views get outlined in different colors.

    Set it "permanently" via

    % defaults write com.apple.TextEdit NSShowAllViews YES
    (or whatever your application identifier is), or use the one-shot version:
    /Developer/Applications/Xcode.app/Contents/MacOS/Xcode -NSShowAllViews YES

  • Responding to a scrollview scrolling (NSScrollView->General) (21 January , 2005) [permalink]
    If you need to react to a scrollview being scrolled by the user, first tell the contentView (the NSClipView) to post notifications when its bounds changes, and then register to receive an NSViewBoundsDidChangeNotification:
        [[scrollView contentView] setPostsBoundsChangedNotifications: YES];
    
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter] ;
        [center addObserver: self
                selector: @selector(boundsDidChangeNotification:)
                name: NSViewBoundsDidChangeNotification
                object: [scrollView contentView]];
    ...
    
    - (void) boundsDidChangeNotification: (NSNotification *) notification
    {
        [self setNeedsDisplay: YES];
        // or whatever work you need to do
    
    } // boundsDidChangeNotification
    

  • Scrolling an NSScrollView programatically (NSScrollView->General) (21 January , 2005) [permalink]
    Sometimes you need to scroll a scrollview outside of user control. You first have to tell the content view (Which is an NSClipView) to scroll to a point, and then tell the scrollview to adjust its scrollbar position:
        [[scrollView contentView] scrollToPoint: pointToScrollTo];
        [scrollView reflectScrolledClipView: [scrollView contentView]];
    

  • Renaming "MyDocument" (Xcode->General) (19 January , 2005) [permalink]
    I find the default name "MyDocument" that Xcode uses for new document-based Cocoa apps to be annoying, sounding more appropriate for Fisher-Price toys than professional software. Renaming all of the moving pieces in Xcode can be a bit daunting, and I don't want to edit the project template, since those tend to get revised as time goes on. This is what I do:
    1. make the new project
    2. replace MyDocument with the newDocument name (BWGraphDocument here):
      perl -pi -e 's/MyDocument/BWGraphDocument/g' *.[hm] *.xcodeproj/* *.plist
    3. rename the document files:
      mv MyDocument.h BWGraphDocument.h
      mv MyDocument.m BWGraphDocument.m
    4. rename the nib file:
      mv MyDocument.nib BWGraphDocument.nib
    5. open the nib file, drag in your document header and change the class of the File's Owner to the new class. Delete the MyDocument type.

  • Seeing what frameworks an application links against (Tools->General) (17 January , 2005) [permalink]
    % otool -L /path/to/application.app/Contents/MacOS/application

  • Setting a cursor for a view (NSView->General) (13 January , 2005) [permalink]
    Sometimes you want to change the cursor for a view, say with a crosshair for a view that lets you select a rectangle out of an image. There is no -[NSView setCursor:]call (drat!) You can get something similar by adding this to your NSView subclass:
    - (void) resetCursorRects
    {
        [super resetCursorRects];
        [self addCursorRect: [self bounds]
              cursor: [NSCursor crosshairCursor]];
    
    } // resetCursorRects

  • Finding things like ~/Library, and ~/Library/Application Services (Random->General) (08 January , 2005) [permalink]
    NSSearchPathForDirectoriesInDomains is how you find the location of things like Library directories, or User directories, and the like (this is theNSSearchPathDirectory). The NSSearchPathDomainMask is what domains to find things in. For instance for a NSLibraryDirectory, a NSUserDomainMask will give you the path to ~/LibraryNSSystemDomainMask will give you the path to /System/Library, and so on.

    The directories inside of Library, like "Preferences" and "Application Support" are in English in the file system, and the Finder presents localized versions to the user. If you need ~/Library/Application Support/Borkware, you can construct it like

       NSMutableString *path;
        path = [[NSMutableString alloc] init];
    
        // find /User/user-name/Library
        NSArray *directories;
        directories = NSSearchPathForDirectoriesInDomains (NSLibraryDirectory,
                                                           NSUserDomainMask, YES);
    
        // if you had more than one user domain, you would walk directories and
        // work with each path
        [path appendString: [directories objectAtIndex: 0]];
    
        [path appendString: @"/Application Support"];
        [path appendString: @"/Borkware"];
    

  • Binding to your AppController (Bindings->General) (07 January , 2005) [permalink]
    If you have an AppController object in your nib file, and it's not File's Owner, but you want to use bindings with it, you can use an NSObjectController :
    1. Make an IBOutlet in your controller to point to the NSObjectController
    2. Drag an NSObjectController into the nib
    3. Add the names of the properties you're going to be binding with
    4. in AppController's awakeFromNib method, do [objController setContent: self];
    By setting the content value in awakeFromNib helps prevent a retain cycle which can lead to memory leaks.

  • Handling unknown keys with KVC (Bindings->General) (07 January , 2005) [permalink]
    Override valueForUndefinedKey::
    - (id) valueForUndefinedKey: (NSString *) key
    {
        id value;
        value = [self lookUpValueUsingSomeOtherMechanism: key];
    
        if (value == nil) {
            value = [super valueForUndefinedKey: key];
        }
    
        return (value);
    
    } // valueForUndefinedKey
    Some handy uses for this is using the user defaults for storing values (you can use the key directly to [NSUserDefaults stringForKey:], or use it to query the contents of an NSDictionary

    The counterpart for this is

    - (void) setValue: (id) value forUndefinedKey: (NSString *) key, which you can use to stash stuff into user prefs or a dictionary.

  • Manually creating a binding (Bindings->General) (07 January , 2005) [permalink]
    [imageView bind: @"valuePath"
               toObject: imagesController
               withKeyPath: @"selection.fullPath"
               options: nil];
    In Interface Builder, "Bind To" corresponds to imagesController, "Controller Key" would be selection, and "Model Key Path would be fullPath.

    Use

        [imageView unbind: @"valuePath"];
    to remove a binding.

  • Finding Mac OS X version from the command line (Unix->General) (03 January , 2005) [permalink]
    % sw_vers
    ProductName:    Mac OS X
    ProductVersion: 10.3.7
    BuildVersion:   7S215
    

  • Make an NSValue out of an NSRect (General->General) (01 December , 2004) [permalink]
        NSRect selectionRect = ...;
        NSValue *value;
        value = [NSValue valueWithRect: selectionRect];
    

  • Checking for modifier keys (NSView->General) (01 December , 2004) [permalink]
    In your mouseDown:
        if ([event modifierFlags] & NSShiftKeyMask) {
            constrain = YES;
        } 
    
    If you need to check them outside of your mouseDown, dip into carbon:
    • GetCurrentEventKeyModifiers returns the modifiers of the last event processed by the event dispatcher. This is usually sufficient.
    • GetCurrentKeyModifiers returns the hardware state of the modifiers.
    Carbon and AppKit use different constants for the modifiers, however, so you may need to convert between them depending on your situation. (Muchos Thankos to Peter Hosey for the Carbon trick)

  • Having powerbook not wake from sleep when the lid opens (General->Hacks) (11 November , 2004) [permalink]
    # pmset lidwake 0

  • Turning off the psql pager (Postgresql->General) (31 October , 2004) [permalink]
    wplug-oacs=# \pset pager
    Pager usage is off.

  • Seeing a lot of gcc's #defines (Tools->General) (20 September, 2004) [permalink]
    % gcc -E -dM -x c /dev/null

    (thanks to xmath on #macdev for this one)

  • Updating critical system files while preserving the original timestamp (Unix->Administration) (18 September, 2004) [permalink]
    Sometimes you need to edit a file, like /etc/rc, but you want to be able to back out your changes. You also want to preserve the original timestamp of the file. That way if you back out your change, someone else coming along doesn't have to figure out "why did /etc/rc change yesterday, it doesn't look any different?" Here's how:
    1. Move (not copy) the original to a backup name. This will preserve the timestamp: % sudo mv rc rc-orig

    2. Copy the original to the usual name: % sudo cp rc-orig rc

    3. make your edits: % sudo vi rc
    If you decide your changes aren't worth keeping, you would move the original back:
    % sudo mv rc-orig rc

    Thereby undoing your changes, and not messing up the timestamp of the original file.

    (mucho thankos to Louis Bertrand for this one)

  • Mounting a disk image from the command line (Unix->General) (08 September, 2004) [permalink]
    % hdiutil mount diskimage.dmg

  • Changing extension for a bundle (Xcode->General) (03 September, 2004) [permalink]
    The default extension for a CocoaBundle is ".bundle". To change it to something else, use the WrapperExtension target property. Select the top-most item in the groups and files list, show the Info panel, choose Styles, and look for Wrapper Extension. Set that to what you want (such as "service"). Don't include the dot.

  • Stripping a string of all HTML tags via a perl script and NSTask (NSTask->General) (20 August , 2004) [permalink]
    Here is a little perl script called stripper.pl which removes everything that looks like an HTML / SGML / XML tag:
    #!/usr/bin/perl
    
    while (<>) {
        $_ =~ s/<[^>]*>//gs;
        print $_;
    }
    
    Be sure to chmod +x the script. Add it to your project, add a new "Copy Files" phase, and have it stick this script into the Executables directory.

    This method will take a string and feed it through the perl script:

    - (NSString *) stringStrippedOfTags: (NSString *) string
    {
        NSBundle *bundle = [NSBundle mainBundle];
        NSString *stripperPath;
        stripperPath = [bundle pathForAuxiliaryExecutable: @"stripper.pl"];
    
        NSTask *task = [[NSTask alloc] init];
        [task setLaunchPath: stripperPath];
    
        NSPipe *readPipe = [NSPipe pipe];
        NSFileHandle *readHandle = [readPipe fileHandleForReading];
    
        NSPipe *writePipe = [NSPipe pipe];
        NSFileHandle *writeHandle = [writePipe fileHandleForWriting];
    
        [task setStandardInput: writePipe];
        [task setStandardOutput: readPipe];
    
        [task launch];
    
        [writeHandle writeData: [string dataUsingEncoding: NSASCIIStringEncoding]];
        [writeHandle closeFile];
    
        NSMutableData *data = [[NSMutableData alloc] init];
        NSData *readData;
    
        while ((readData = [readHandle availableData])
               && [readData length]) {
            [data appendData: readData];
        }
    
        NSString *strippedString;
        strippedString = [[NSString alloc]
                             initWithData: data
                             encoding: NSASCIIStringEncoding];
    
        [task release];
        [data release];
        [strippedString autorelease];
    
        return (strippedString);
    
    } // stringStrippedOfTags

  • Converting mac newlines to unix newlines in a text file (Unix->General) (29 July , 2004) [permalink]
    tr '\r' '\n' < macfile.txt > unixfile.txt
    

  • Am I Being Debugged? (Debugging->General) (28 July , 2004) [permalink]
    int AmIBeingDebugged(void)
    {
            int                                        mib[4];
            struct kinfo_proc        info;
            size_t                                size;
            
            mib[0] = CTL_KERN;
            mib[1] = KERN_PROC;
            mib[2] = KERN_PROC_PID;
            mib[3] = getpid();
            size = sizeof(info);
            info.kp_proc.p_flag = 0;
            sysctl(mib,4,&info,&size,NULL,0);
            return ((info.kp_proc.p_flag & P_TRACED) == P_TRACED);
    }
    
    #define StopIfInDebugger()        __asm__ volatile ("twnei %0,0" : : "r" (AmIBeingDebugged()))
    (courtesy of arwyn on #macdev. Useful uses: controlling voluminous console output when running in gdb, or if running non-debugged, an assert routine that generates stack trace and logs it when not-being debugged, but just traps into the debugger at the point of failure when being debugged)

  • Fixing undefined symbols when building plugins (Xcode->General) (01 July , 2004) [permalink]
    If you have a plugin defined as a "Cocoa Bundle" target in Xcode, and your plug-in inherits from a class that's defined in the application, you may get a build error like:
    ld: Undefined symbols:
    .objc_class_name_BWTrackerPlugin
    
    You can fix this by adding -undefined dynamic_lookup to the "Other Linker Flags" of the Build Tab of the Target Settings for your plugin (whew!). You also need to make sure that the "Mac OS X Deployment Target" is 10.2 or later before using this flag.

  • Grabbing a view into an image (NSView->General) (03 April , 2004) [permalink]
    In your NSView subclass:
    [self lockFocus];
    
    NSBitmapImageRep *bits;
    bits = [[NSBitmapImageRep alloc]
               initWithFocusedViewRect: [self bounds]];
    [self unlockFocus];
    
    Then you can add it to an NSImage or save it to a file, or whatever.

    If you want to retain the vectoritude of the drawing, you can use [self dataWithPDFInsideRect: [self bounds]], and then make an NSPDFImageRep. Avoid theNSEPSImageRep since it makes a trip through NSPDFImageRep along with a slow PS to PDF conversion. (Thanks to Peter Hosey for the PDF hint)

  • Saving an image as a file (NSImage->General) (03 April , 2004) [permalink]
    To save an imageRep as a PNG file:
    NSBitmapImageRep *bits = ...; // get a rep from your image, or grab from a view
    
    NSData *data;
    data = [bits representationUsingType: NSPNGFileType
                 properties: nil];
    [data writeToFile: @"/path/to/wherever/test.png"
          atomically: NO];
    
    There are also TIFF, BMP, GIF, JPEG file types in addition to PNG.

  • pg interval math (Postgresql->General) (07 March , 2004) [permalink]
    Older versions of pg would support select blah from whatever where date-column > (current_timestamp - 21) to get all the blahs from whatever in the last 21 days. This doesn't work in newer versions of Postgresql. Instead, you need to use a time interval:
    select to_char (whenx, 'fmDD fmMonth YYYY') as pretty_when, text
      from blog
     where whenx > (current_timestamp - interval '21 days')
     order by whenx desc
    

  • Making a custom event tracking runloop (NSView->General) (12 February , 2004) [permalink]
    Sometimes in your mouse tracking code you want to use the NSEventTrackingRunLoopMode, such as you wanting to use an NSNotificationQueue to coalesce updates for your own mouse tracking code. I've been sticking a call to this in my mouseDown: handler for the cases when I want the secondary run loop
    - (void) runEventTrackingRunLoop
    {
        NSEventType eventType = NSLeftMouseDown;
    
        unsigned int eventMask = NSLeftMouseDownMask | NSLeftMouseUpMask
            | NSLeftMouseDraggedMask | NSMouseMovedMask;
    
        while (eventType != NSLeftMouseUp) {
            NSEvent *event;
            event = [NSApp nextEventMatchingMask: eventMask
                           untilDate: [NSDate distantFuture]
                           inMode: NSEventTrackingRunLoopMode
                           dequeue: YES];
    
            eventType = [event type];
    
            if (eventType == NSLeftMouseDragged) {
                [self mouseDragged: event];
            }
        }
    
    } // runEventTrackingRunLoop
    
    (and thanks to Rainer Brockerhof for pointing out a no-op line of code from the original version of this)

  • Finding parent process IDs on Linux (Unix->General) (29 January , 2004) [permalink]
    % ps -eo "%p %P %c"

  • Printing method arguments (gdb->General) (29 January , 2004) [permalink]
    If you've hit a breakpoint on a method that doesn't have debug symbols, you can sometimes get useful information by looking in the processor registers. Arguments start in $r3 and go up from there. For Objective-C method sends, $r3 has 'self', and $r4 has the name of the method. Subsequent arguments are in $5 and so on.
    (gdb) print (char*) $r4
    $5 = 0x90874160 "drawRect:"
    
    (gdb) po $r5
    <BWStitchView: 0x1a6670>
    
    

  • Mapping a window to its document (NSDocument->General) (25 January , 2004) [permalink]
        NSDocumentController *documentController;
        documentController = [NSDocumentController sharedDocumentController];
    
        BWBorkStitchDocument *noteDocument;
        noteDocument = [documentController documentForWindow: noteWindow];

  • Adding AppleHelp (Xcode->General) (21 January , 2004) [permalink]
    1. Create a "AppName Help" directory in your English.lproj.

    2. Add an index.html Put in these headers:
      <head>
        <meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
        <title>AppName Help</title>
        <meta name="AppleTitle" content="AppName Help">
        <meta name="AppleIcon" content="AppName%20Help/images/icon-name.png">
        <meta name="AppleFont" content="Lucida Grande,Helvetica,Arial">
        <meta name="AppleSearchResultsFont" content="Lucida Grande,Geneva,Arial">
        <meta name="robots" content="noindex">
      </head>
      
      Along with your actual help content.

    3. Drag the AppName Help directory into your XCode project. When Adding, make sure "Copy items into destination group's folder" is unchecked, and select "Create Folder References for any add folders". You wnat XCode to preserve your AppName Help directory.

    4. Add these to your Info.plist:
      <key>CFBundleHelpBookFolder</key>
      <string>AppName Help</string>
      <key>CFBundleHelpBookName</key>
      <string>AppName Help</string>
      

    5. Build, run, and cross your fingers. If Help.app is already running, you may want to exit it.

  • Turning off Panther's "Program quit - send a report to Apple" dialog (Debugging->General) (19 January , 2004) [permalink]
    During development, it's annoying to get the "Your program just crashed! Send a report to Apple?". You can turn that off by entering this in the terminal:

    % defaults write com.apple.CrashReporter DialogType none

    Turn turn it back on, replace none with prompt to get the original behavior. See for details.

  • Detecting arrow keys (NSView->General) (18 January , 2004) [permalink]
    - (void) keyDown: (NSEvent *) event
    {
        NSString *characters;
        characters = [event characters];
    
        unichar character;
        character = [characters characterAtIndex: 0];
    
        if (character == NSRightArrowFunctionKey) {
            [self moveSelectedBlockBy: 1];
    
        } else if (character == NSLeftArrowFunctionKey) {
            [self moveSelectedBlockBy: -1];
    
        }  ... and look at whatever other keys you want
    }
    

  • Storing window position in the document (NSDocument->General) (18 January , 2004) [permalink]
    If you want to store the window position in your document, you'll need to store and restore the [window frame] of the window in question. (That's left as an exercise to the reader, based on how you're storing your document contents.) When restoring the window location, you have to turn of NSWindowController's cascading, otherwise it'll honor your width and height, but not your origin. In your document's windowControllerDidLoadNib method, you'll need:
        [[self windowController] setShouldCascadeWindows: NO];
    
        NSWindow *window;
        window = [self window];
        [window setFrame: loadedWindowBounds display: YES];
    

  • Making a delegate (NSObject->General) (18 January , 2004) [permalink]
    You've decided you want your class to have a delegate. Here's how you go about doing it:
    1. Make an id instance variable in your class, and make methods to set and get it:
      id   delegate;
      ...
      -(void) setDelegate: (id) del
      {
          delegate = del; // you don't need to retain it
      } // setDelegate
      
      - (id) delegate
      {
          return (delegate);
      } // delegate
      

    2. Make a category on NSObject so the compiler won't generate warnings, and also to document the delegate methods you support:
      @interface NSObject(BWStitchViewDelegate)
      - (BOOL) shouldHandleStuff: (NSData *) data;
      @end
      

    3. Check to make sure your delegate understands the message before sending it.
      ...
      if ([delegate respondsToSelector: @selector(shouldHandleStuff:)]) {
          BOOL blah;
          blah = [delegate shouldHandleStuff: somedata];
          if (blah) ...
      }
      

  • Command-line building from xcode (Xcode->General) (15 January , 2004) [permalink]
    xcodebuild is the pbxbuild equivalent. To get a development build, you'll need to specify the style:
    % xcodebuild -buildstyle Development

  • XCode's default projects (Xcode->General) (15 January , 2004) [permalink]
    XCode looks in /Library/Application Support/Apple/Developer Tools/Project Templates/ for the templates for its projects. You can put your own project templates here, and tweak the existing templates (for instance, Xcode 1.1's Cocoa projects have a compiler warning in main.m, which is really annoying for those of use who treat warnings as errors. You can go into /Library/Application Support/Apple/Developer Tools/Project Templates/Application/Cocoa Application/ and fix that warning if you wish.

  • Making a timestamp with strftime (Unix API->General) (14 January , 2004) [permalink]
        time_t now;
        now = time(NULL);
    
        struct tm *tm;
        tm = localtime (&now);
    
        char timestamp[200];
        strftime (timestamp, 200, "%m/%d/%Y-%H:%M", tm);
    

  • Printing object retain count in gdb (gdb->General) (12 January , 2004) [permalink]
    In the gdb console:
    (gdb) print (int)[theObject retainCount]

    If you're expecting to have an excessively high number of retains, you can use (unsigned int) in the cast. I find (int) a skootch faster to type.

  • calling objective-C methods in gdb (gdb->General) (12 January , 2004) [permalink]
    To call an Objective-C method in the gdb console, you have to cast the return type (since gdb doesn't really know what the return value is):
    (gdb) call (void)[textField setStringValue: @"Bork"]
    

  • Respond to every keystroke in a textfield (NSControl->General) (12 January , 2004) [permalink]
    Make your object a delegate of the textfield, and add this NSControl delegate method:
    - (void) controlTextDidChange: (NSNotification *) notification
    {
        // do work here, like count the characters or something
    } // controlTextDidBeginEditing
    

  • Open documentation for a symbol (Xcode->General) (12 January , 2004) [permalink]
    Say you have "NSFishmonger" in your code, and you want to see the header. Option-double-click on NSFishmonger and it will bring up the header file.

  • Open header for a symbol (Xcode->General) (12 January , 2004) [permalink]
    Say you have "NSColor" in your code, and you want to see the header. Command-double-click on NSColor and it will bring up the header file.

  • Toggle between the source file and its header file. (Xcode->General) (12 January , 2004) [permalink]
    comand-option-up arrow

  • Case-insensitive file completion with bash (Unix->General) (08 January , 2004) [permalink]
    If you use bash as your shell and use filename completion a lot, you can get bash to ignore the case of filenames just like HFS does. Just put this in your ~/.inputrc file:

    set completion-ignore-case On

    Then when you type ls /appli in the shell you'll get ls /Applications/ like you ought to!

  • Simple archiving (NSCoder->General) (04 January , 2004) [permalink]
    To archive a single object (which can be something like an array or dictionary that contains other object), such as saving your document, do:
    - (NSData *) dataRepresentationOfType: (NSString *) aType
    {
        NSData *data;
        data = [NSArchiver archivedDataWithRootObject: group];
    
        return (data);
    
    } // dataRepresentationOfType
    

  • Simple unarchiving (NSCoder->General) (04 January , 2004) [permalink]
    To unarchive a single object (which can be something like an array or dictionary that contains other object), such as loading your document, do:
    - (BOOL) loadDataRepresentation: (NSData *) data
                             ofType: (NSString *) aType
    {
        // replace the moedl
        [group release];
        group = [NSUnarchiver unarchiveObjectWithData: data];
        [group retain];
    
        // make any associations to hook the new data into your document
    
        return (YES);
    
    } // loadDataRepresentation
    
    

  • Fixing strange duplicate symbols (Random->Random) (01 January , 2004) [permalink]
    While compiling OpenSP, the SGML parser for OpenJade, I got these errors:
    ld: multiple definitions of symbol OpenSP::Text::~Text [in-charge]()
    Entity.lo definition of OpenSP::Text::~Text [in-charge]() in section (__TEXT,__text)
    Group.lo definition of OpenSP::Text::~Text [in-charge]() in section (__TEXT,__text)
    ld: multiple definitions of symbol OpenSP::Text::~Text [not-in-charge]()
    Entity.lo definition of OpenSP::Text::~Text [not-in-charge]() in section (__TEXT,__text)
    Group.lo definition of OpenSP::Text::~Text [not-in-charge]() in section (__TEXT,__text)
    Param.lo definition of OpenSP::Text::~Text [in-charge]() in section (__TEXT,__text)
    Param.lo definition of OpenSP::Text::~Text [not-in-charge]() in section (__TEXT,__text)
    
    These are caused by the class in question (Text) not having an explicit destructor declared, so the compiler is creating one for us in each of the files. In Text.cxx, add
    Text::~Text() { }
    
    and in Text.h, add
    ~Text();
    
    to the Text class. (I got it to compile and link, so I didn't go back to check to see if just sticking ~Text() {} in Text.h would work.)

  • Fixing strange undefined link symbols (Random->Random) (01 January , 2004) [permalink]
    While building OpenJade, I got these link errors:
    gcc -dynamiclib  -o .libs/libogrove.0.0.1.dylib  Node.lo LocNode.lo  -lm -lc -install_name  /usr/local/lib/libogrove.0.dylib
    ld: Undefined symbols:
    vtable for __cxxabiv1::__class_type_info
    vtable for __cxxabiv1::__si_class_type_info
    operator delete(void*)
    operator new(unsigned long)
    ___cxa_pure_virtual
    ___gxx_personality_v0
    /usr/bin/libtool: internal link edit command failed
    
    The link line needs to have "-lstdc++" added to the end. For OpenJade, edit the libtool script and add -lstdc++ to the end archive_cmds line. (but leave it inside the last closing double-quote)

  • Seeing media types supported by your CD/DVD burner (Unix->Random) (24 December , 2003) [permalink]
    On Panther, you can run /usr/bin/drutil info to get a listing of the kinds of media your drive supports. For example, on the 17" iLamp:
    % drutil info
     Vendor   Product           Rev 
     PIONEER  DVD-RW  DVR-104   A227
    
       Interconnect: ATAPI
       SupportLevel: Apple Shipping
              Cache: 2000k
           CD-Write: -R, -RW, BUFE, Test, IndexPts, ISRC
          DVD-Write: -R, -RW, BUFE, Test
         Strategies: CD-TAO, CD-SAO, DVD-DAO
    

  • Dragging feedback only between rows (NSTableView->General) (20 October , 2003) [permalink]
    When rearranging rows in a tableview, the user feedback should just go between rows (the whole-row highlighting is confusing). In the drop validation method only let things through for NSTableViewDropAbove
    - (NSDragOperation) tableView: (NSTableView*) tableView
                     validateDrop: (id ) info
                      proposedRow: (int) row
            proposedDropOperation: (NSTableViewDropOperation) op
    {
        int result = NSDragOperationNone;
    
        if (op == NSTableViewDropAbove) {
            result = NSDragOperationMove;
        }
    
        return (result);
    
    } // validateDrop
    
    

  • Preventing the return key from editing the next cell (NSTableView->General) (20 October , 2003) [permalink]
    The default tableview behavior, when editing a row, is to move the field editor to the next cell when the user commits editing using the Return key. If you want Return to commit the editing and dismiss the field editor, subclass NSTableView and add this:
    - (void) textDidEndEditing: (NSNotification *) notification
    {
        NSDictionary *userInfo;
        userInfo = [notification userInfo];
    
        NSNumber *textMovement;
        textMovement = [userInfo objectForKey: @"NSTextMovement"];
    
        int movementCode;
        movementCode = [textMovement intValue];
    
        // see if this a 'pressed-return' instance
    
        if (movementCode == NSReturnTextMovement) {
            // hijack the notification and pass a different textMovement
            // value
    
            textMovement = [NSNumber numberWithInt: NSIllegalTextMovement];
    
            NSDictionary *newUserInfo;
            newUserInfo = [NSDictionary dictionaryWithObject: textMovement
                                        forKey: @"NSTextMovement"];
    
            notification = [NSNotification notificationWithName:
                                               [notification name]
                                           object: [notification object]
                                           userInfo: newUserInfo];
        }
    
        [super textDidEndEditing: notification];
    
    } // textDidEndEditing
    

  • Putting the ordering triangles in table columns (NSTableView->General) (13 October , 2003) [permalink]
    Put this somewhere (maybe in your mouseDownInHeaderOfTableColumn or didClickTableColumn:
        NSImage *indicatorImage;
        if (sortAscending) {
            sort your data ascending
            indicatorImage = [NSImage imageNamed: @"NSAscendingSortIndicator"];
        } else {
            sort your data descending
            indicatorImage = [NSImage imageNamed: @"NSDescendingSortIndicator"];
        }
        sortAscending = !sortAscending;
    
        [tableView setIndicatorImage: indicatorImage
                       inTableColumn: tableColumn];
    
        [tableView reloadData];
    
    

  • Responding to selection changes (NSTableView->General) (13 October , 2003) [permalink]
    - (void) tableViewSelectionDidChange: (NSNotification *) notification
    {
        int row;
        row = [tableView selectedRow];
    
        if (row == -1) {
            do stuff for the no-rows-selected case
        } else {
            do stuff for the selected row
        }
    
    } // tableViewSelectionDidChange
    If you have more than one tableview, the notification's object is the tableview that had the selection change.

  • Seeing the selectors objects ask you about (NSObject->General) (13 October , 2003) [permalink]
    Sometimes it's handy to see when someone is asking your object what selectors it reponds to. Stick this in your class and you can see what folks are asking for:
    - (BOOL) respondsToSelector: (SEL) aSelector
    {
        NSLog (@"%s", (char *) aSelector);
        return ([super respondsToSelector: aSelector]);
    
    } // respondsToSelector
    
    This takes advantage of an implementation detail where the SEL is actually a pointer to a C string

  • Today's date (NSDate->General) (13 October , 2003) [permalink]
    NSDate *today;
    today = [NSDate date];

  • Finding a subview based on tag (NSView->General) (05 October , 2003) [permalink]
    Sometimes you're in a situation where you need to get ahold of a view and it's not convenient to set up stuff in IB (like the object needing to get the view isn't in the nib file with the window). You can uses NSView's viewWithTag: to find it.

  • Converting .snd resource to aiff (NSSound->General) (03 October , 2003) [permalink]
    Get SoundApp PPC (a classic App). Choose File->Convert, set these attributes:
    • Format : AIFF
    • Encoding : PCM
    • Rate : 44100 Hz
    • Bits : 16 bits
    and save. Then you can load it and play it with NSSound

    Addendum: NSSound is based on Core Audio and QuickTime as of 10.3, so it may be able to play .snd resource files as-is. So give that a try if you don't need to support 10.2 or earlier. (Thanks to Peter Hosey for the clarification.)

  • Make emacs indent code with spaces instead of tabs (emacs->General) (26 September, 2003) [permalink]
    Personally, I prefer emacs' default indentation with a mixture of tabs and spaces. If you're working on a project or for a client that requires indentation with spaces, add this to your .emacs file. This will make spaces the indent character, and use 4 spaces per indent level, for C, C++, and Objective C:

    (setq c-mode-hook
        (function (lambda ()
                    (setq indent-tabs-mode nil)
                    (setq c-indent-level 4))))
    (setq objc-mode-hook
        (function (lambda ()
                    (setq indent-tabs-mode nil)
                    (setq c-indent-level 4))))
    (setq c++-mode-hook
        (function (lambda ()
                    (setq indent-tabs-mode nil)
                    (setq c-indent-level 4))))
    

  • compiling emacs .el files (emacs->General) (26 September, 2003) [permalink]
    Big emacs .el files take a long time to load. You can compile them into .elc files by using:
    % emacs -batch -f batch-byte-compile filename.el

  • Preventing NSPanels from hiding on program deactivation (NSWindow->General) (25 July , 2003) [permalink]
    Sometimes you want an NSPanel for the nice skinny title bar, but don't want it to hide when another program is made active. Somewhere convenient (like in the awakeFromNib), do something like

    [panel setHidesOnDeactivate: NO];

  • Tableview DataSource methods (NSTableView->General) (25 July , 2003) [permalink]
    Your datasource needs to implement these two bad boys:

    - (int) numberOfRowsInTableView: (NSTableView *) tableView
    - (id) tableView: (NSTableView *) tableView
    objectValueForTableColumn: (NSTableColumn *) tableColumn
    row: (int) row

  • Using tree_sortkey (Postgresql->General) (25 July , 2003) [permalink]
    Jade Rubick has some brief documentation on using the postgresql tree_sortkey stuff.

  • Posting notifications. (Notifications->General) (08 June , 2003) [permalink]
    In the header file:

    extern NSString *BWStitchGroup_VisualAttributeChangeNotification;

    In the .m file:

    NSString *BWStitchGroup_VisualAttributeChangeNotification
        = @"BWStitchGroup Visual Attribute Change Notification";

    ...

    NSNotificationCenter *center;
    center = [NSNotificationCenter defaultCenter];
    
    [center postNotificationName: 
                BWStitchGroup_VisualAttributeChangeNotification
            object: self];
    If you want to pass a userinfo dictionary, you can use a variant method:
        NSDictionary *userInfo = ...;
        [center postNotificationName: BWStitchGroup_VisualAttributeChangeNotification
                object: self
                userInfo: userInfo];
    

  • Receiving notifications (Notifications->General) (08 June , 2003) [permalink]
    NSNotificationCenter *center;
    center = [NSNotificationCenter defaultCenter];
    
    [center addObserver: self
            selector: @selector(groupVisualChange:)
            name: BWStitchGroup_VisualAttributeChangeNotification
            object: group];
    
    Where the selector looks like this:
    - (void) groupVisualChange: (NSNotification *) notification
    {
        // do stuff with the notification
    } // groupVisualChange

  • My color well has a little triangle on it? (NSColorWell->General) (02 June , 2003) [permalink]
    If your color well has a little triangle in the corner after you set the color programatically, that probably means the NSColor you used was created in Device space (e.g.colorWithDeviceRed:green:blue:alpha:) If you use a Calibrated color (colorWithCalibratedRed:green:blue:alpha:), the triangle goes away.

  • Apple's recommended retain/release technique (NSObject->General) (01 June , 2003) [permalink]
    This way if "get" performance is important:
    - (NSString*) title
    {
        return (title);
    } // title
    
    - (void) setTitle: (NSString *) newTitle
    {
        [title autorelease];
        title = [newTitle copy];
    } // setTitle
    
    For maximum safety in the face of threads, use this:
    - (NSString *) title
    {
        return [[title retain] autorelease];
    } // title
    
    This puts title into the current thread's autorelease pool, so title is protected from being destroyed by someone else in another thread.
    - (void) setTitle: (NSString *) newTitle
    {
        // use a mutex or NSLock to protect this
        if (title != newtitle) {
            [title release];
            title = [newTitle copy];
        }
    } // setTitle
    
    By making a copy of the object, you're protected from another thread changing the value underneath you.

  • Should you retain the delegate in your objects? (NSObject->General) (01 June , 2003) [permalink]
    If you're creating an object, and you provide a delegate feature, should you retain the delegate? Nope! These objects are peers, not an owner/owned, or parent/child relationship. If you free your object, you shouldn't need to worry about memory management of your delegate. Likewise, if someone releases the delegate object, they should clean up after themselves and tell you to have a nil delegate.

  • Getting a document's window (NSDocument->General) (28 April , 2003) [permalink]
    For 10.3 and later systems, use -windowForSheet (which doesn't tell you the window associated with a particular sheet, but instead returns the window to be used for showing sheets, which is usually what you want when talking about the document's window - Thanks to Peter Hosey for this one).

    For folks stuck in 10.2 land, or who want to do it themselves, there's always this:

    - (NSWindow *) window
    {
        NSArray *windowControllers;
        windowControllers = [self windowControllers];
    
        NSWindowController *controller;
        controller = [windowControllers objectAtIndex: 0];
    
        NSWindow *window;
        window = [controller window];
    
        return (window);
    
    } // window

  • Seeing all the flags gcc takes (Unix->General) (26 April , 2003) [permalink]
    % gcc -v --help

  • Making a floating palette (NSWindow->General) (25 April , 2003) [permalink]
    To make a floating palette with small controls, make the palette an NSPanel, and n IB make it a "Utility Window".

  • Using sockets with cocoa (Samples->General) (24 April , 2003) [permalink]
    networkolizer.tar.gz is a very short sample that opens a socket connection (using the Berkeley sockets API), and then writes an HTTP request, and reads the response.

  • Launching a task (NSTask->General) (23 April , 2003) [permalink]
    Here are the basics to launch "ls -l -a -t" in the current directory, and then read the result into an NSString:
        NSTask *task;
        task = [[NSTask alloc] init];
        [task setLaunchPath: @"/bin/ls"];
    
        NSArray *arguments;
        arguments = [NSArray arrayWithObjects: @"-l", @"-a", @"-t", nil];
        [task setArguments: arguments];
    
        NSPipe *pipe;
        pipe = [NSPipe pipe];
        [task setStandardOutput: pipe];
    
        NSFileHandle *file;
        file = [pipe fileHandleForReading];
    
        [task launch];
    
        NSData *data;
        data = [file readDataToEndOfFile];
    
        NSString *string;
        string = [[NSString alloc] initWithData: data
                                   encoding: NSUTF8StringEncoding];
        NSLog (@"woop!  got\n%@", string);
    Of course, you can use different NSFileHandle methods for different styles of reading, and you can make a pipe for standard input so you can feed data to the task.

  • Performing complex pipelines. (NSTask->General) (23 April , 2003) [permalink]
    You can create multiple NSTasks and a bunch of NSPipes and hook them together, or you can use the "sh -c" trick to feed a shell a command, and let it parse it and set up all the IPC. This pipeline cats /usr/share/dict/words, finds all the words with 'ham' in them, reverses them, and shows you the last 5.
        NSTask *task;
        task = [[NSTask alloc] init];
        [task setLaunchPath: @"/bin/sh"];
    
        NSArray *arguments;
        arguments = [NSArray arrayWithObjects: @"-c",
                             @"cat /usr/share/dict/words | grep -i ham | rev | tail -5", nil];
        [task setArguments: arguments];
        // and then do all the other jazz for running an NSTask.
    One important note:, don't feed in arbitrary user data using this trick, since they could sneak in extra commands you probably don't want to execute.

  • Supporting decoding (NSCoder->General) (22 April , 2003) [permalink]
    - (id) initWithCoder: (NSCoder *) aDecoder
    {
        if (self = [super init]) {
            // or else [super initWithCoder: aDecoder] if your superclass
            // supports it.  NSObject does not.
    
            // decoding a C type
            [aDecoder decodeValueOfObjCType: @encode(int)
                      at: &itemCount];
    
            // decoding an array of C structs
            if (items != NULL) {
                free (items);
            }
            items = malloc (sizeof(BWRawPathItem) * itemCount);
    
            int i;
            for (i = 0; i < itemCount; i++) {
                [aDecoder decodeValueOfObjCType: @encode(BWRawPathItem)
                          at: &items[i]];
            }
    
            // decoding an object
            name = [aDecoder decodeObject];
            [name retain];
    
            // any other random initializations that don't come from
            // the encoder
            fooby = -1;
        }
    
        return (self);
    
    } // initWithCoder

  • Supporting encoding (NSCoder->General) (22 April , 2003) [permalink]
    - (void) encodeWithCoder: (NSCoder *) aCoder
    {
        // [super encodeWithCoder:] if you inherit from a class
        // that supports encoding.  NSObject does not.
    
        // encoding a C type
        [aCoder encodeValueOfObjCType: @encode(int)
                at: &itemCount];
    
        // encoding an array of C structs
        int i;
        for (i = 0; i < itemCount; i++) {
            [aCoder encodeValueOfObjCType: @encode(BWRawPathItem)
                    at: &items[i]];
        }
    
        // encoding an object
        [aCoder encodeObject: name];
    
    } // encodeWithCoder

  • Reading a file as an NSData (General->General) (20 April , 2003) [permalink]
        NSString *filename = @"/this/is/my/file/path";
    
        NSData *data;
        data = [NSData dataWithContentsOfFile: filename];
    

  • Moving a file to a tilde file (NSFIleManager->General) (20 April , 2003) [permalink]
        NSString *filename = @"/my/original/file/name";
        NSString *tildeFilename;
        tildeFilename = [NSString stringWithFormat: @"%@~", filename];
    
        // remove it first, otherwise the move will fail
        [defaultManager removeFileAtPath: tildeFilename
                        handler: nil];
    
        // now rename the file
        [defaultManager movePath: filename
                        toPath: tildeFilename
                        handler: nil];
    If you want to stick the tidle before the file extension (so the finder could open ook~.tiff), try this:
    	NSString *pathExtension = [filename pathExtension];
    	if (!pathExtension) {
    		tildeFilename = [filename stringByAppendingString: @"~"];
    	} else {
    		tildeFilename = [NSString stringWithFormat: @"%@~.%@", [filename stringByDeletingPathExtension], pathExtension];
    	}
    (Thanks to Peter Hosey for this one)

  • Removing a file (NSFIleManager->General) (20 April , 2003) [permalink]
        NSFileManager *defaultManager;
        defaultManager = [NSFileManager defaultManager];
    
        [defaultManager removeFileAtPath: tildeFilename
                        handler: nil];
    The handler is an object that will be sent message, like fileManager:shouldProceedAfterError: if something goes wrong during the removal.

  • Saving an NSData to a file (NSFIleManager->General) (20 April , 2003) [permalink]
        NSString *filename = @"/this/is/my/file/name";
        NSData *data = // get NSData from somewhere, like NSPropertyListSerialization
    
       [data writeToFile: filename  atomically: NO];

  • Reading property lists from XML (XML->General) (20 April , 2003) [permalink]
    This will read property lists in XML (or any of the other property list formats:)
        NSData *data = // get NSData from somewhere, like NSFileManager
        if (data) {
            myRootObject = [NSPropertyListSerialization
                               propertyListFromData: data
                               mutabilityOption: NSPropertyListMutableContainers
                               format: nil
                               errorDescription: nil];
        }
    
    For the mutability options of the resulting object, you can also use NSPropertyListImmutable and NSPropertyListMutableContainersAndLeaves

  • Saving property lists as XML (XML->General) (20 April , 2003) [permalink]
    You can save any of the "property list" classes (NSDictionaryNSArray,NSNumberNSStringNSData) as XML like this:
        NSData *data;
        data = [NSPropertyListSerialization
                   dataFromPropertyList: notes
                   format: NSPropertyListXMLFormat_v1_0
                   errorDescription: nil];
    Then write out the data using NSFileManager, or whatever other mechanism you wish.

  • Finding suid executables (Unix->General) (02 April , 2003) [permalink]
    To find setuid executables, run

    % find . -type f -perm +06000 -print

    (or use find / to start looking from the root directory.)

  • Handling double-clicks in a browser (NSBrowser->General) (15 March , 2003) [permalink]
    - (void) awakeFromNib
    {
        [browser setTarget: self];
        [browser setDoubleAction: @selector(browserDoubleClick:)];
    } // awakeFromNib
    
    ...
    
    - (IBAction) browserDoubleClick: (id) sender
    {
        int column = [browser selectedColumn];
        int row = [browser selectedRowInColumn: column];
    
        // then dig into your data structure with the row and column
    
    } // browserDoubleClick

  • NSLog without the extra crud (NSString->General) (06 March , 2003) [permalink]
    NSlog puts too much crud in front of the logging line. For a foundation tool that output stuff, it gets in the way. I'd still like for a replacement to expand %@, which theprintf() family won't do. Here's a some code that'll do that.
    #include <stdarg.h>
    
    void LogIt (NSString *format, ...)
    {
        va_list args;
    
        va_start (args, format);
    
        NSString *string;
    
        string = [[NSString alloc] initWithFormat: format  arguments: args];
    
        va_end (args);
    
        fprintf (stderr, "%s\n", [string UTF8String]);
    
        [string release];
    
    } // LogIt
    

  • Scroll line with cursor to the top of the window (emacs->General) (27 February , 2003) [permalink]
    C-U 0 C-L

    (you can put in another number besides zero to scroll the line with the cursor to that particular line in the buffer)

  • Showing current column position (emacs->General) (27 February , 2003) [permalink]
    M-x column-number-mode

  • Undo within a given region (emacs->General) (27 February , 2003) [permalink]
    C-U C-_

  • Inserting a time column (Postgresql->General) (08 February , 2003) [permalink]
    If you have the minutes, seconds, and am/pm and want to get them into a time column (time without timezone), you can do something like this:

    psql=# select to_timestamp('10:45am', 'HH12:MIam')::timetz::time;
     to_timestamp
    --------------
     10:45:00
    (1 row)
    

  • Increasing shared memory limits (Unix->Administration) (06 February , 2003) [permalink]
    Edit /System/Library/StartupItems/SystemTuning/SystemTuning

    tweak some values, like

    sysctl -w kern.sysv.shmmax=167772160 # bytes: 160 megs
    sysctl -w kern.sysv.shmmin=1
    sysctl -w kern.sysv.shmmni=32
    sysctl -w kern.sysv.shmseg=8
    sysctl -w kern.sysv.shmall=65536 # 4k pages: 256 megs
    
    Save, and restart your system.

    On some Panther seeds, you may need to add these things to /etc/rc

  • Increasing memory buffer sizes (Postgresql->Administration) (06 February , 2003) [permalink]
    If you try upping your shared_buffers in your postgresql.conf, and get an error similar to this:
    IpcMemoryCreate: shmget(key=5432001, size=266371072, 03600) failed: 
    Invalid argument
    This error usually means that PostgreSQL's request for a shared memory
    segment exceeded your kernel's SHMMAX parameter. 
    
    You should increase your the shmmax parameters using tips in the Unix administration quickies.

  • Limiting selections to X number of rows (Postgresql->General) (18 January , 2003) [permalink]
    use the "limit" statement:
    select stuff from some_table
     where stuff.blah > 12
     limit 5
    

  • Selecting a random row from a table (Postgresql->General) (18 January , 2003) [permalink]
    use the random() function.
        select stuff.src, stuff.width, stuff.height from
            (select src, width, height,
                    random()
               from bw_eyes
              order by 4) stuff
        limit 1
    
    This selects a random row from bw_eyes and returns the interesting data from it. This query is used on the quickies pages to randomly select an image of eyes staring back.

  • Time interval math to integer (Postgresql->General) (18 January , 2003) [permalink]
    If you take the difference between two timestamps, you can end up with an unweildly value like "00:06:14.37086 days old". You can cast the timestamps into just regular dates like:
    select current_timestamp()::date - entry_date::date as days_old from kb_nuggets;

  • Connecting to a user / database (Postgresql->General) (30 December , 2002) [permalink]
    Say you have your primary database user as 'nsadmin', and they have a database called 'openacs'. If you're using the default pg_hba.conf, you can connect to the database, logged in as an ordinary person, by doing

    % psql -U nsadmin opeancs

  • Verifying Localizable.strings (General->General) (28 December , 2002) [permalink]
    if there's an error in Localizable.string, your NSLocalizedString() call will not look up the strings in the file. To verify the file, do something like this:

    % pl < Localizable.strings

  • Revisiting / reloading a file in emacs (emacs->General) (28 December , 2002) [permalink]
    The $Id: $ tags for CVS are nice, but it can be a pain when you're doing lots of checkins and have to re-load the file each time. You can either execute M-x revert-bufer or bind that to a key, or else use a trick by doing C-x C-v which invokes find-alternate-file, but just so happens to have the current buffer name, so you just have to do C-x C-v RET

  • Cheap profiling (Unix API->General) (28 December , 2002) [permalink]
    You can use gettimeofday() to get sub-second granularity for timing:
    #include <sys/time.h>
    struct timeval start, end;
    ...
    gettimeofday (&start, NULL);
    
    ... the code you're timing
    
    gettimeofday (&end, NULL);
    double fstart, fend;
    fstart = (start.tv_sec * 1000000.0 + start.tv_usec) / 1000000.0;
    fend = (end.tv_sec * 1000000.0 + end.tv_usec) / 1000000.0;
    NSLog (@"it took %f seconds", fend - fstart);
    

  • Loading a nib file (General->General) (27 December , 2002) [permalink]
    if ([NSBundle loadNibNamed: @"theNibName.nib"  owner: self]) {
        ... life is happy
    } else {
        ... couldn't load the nib
    }
    

  • Deleting the selected text (NSTextView->General) (27 December , 2002) [permalink]
    [textView delete: nil]

  • Moving insertion point to the end (NSTextView->General) (27 December , 2002) [permalink]
    NSRange range = { [[textView string] length], 0 };
    [textView setSelectedRange: range];

  • Moving insertion point to the start (NSTextView->General) (27 December , 2002) [permalink]
    NSRange zeroRange = { 0, 0 };
    [textView setSelectedRange: zeroRange];

  • scrolling to the beginning of a textview (NSTextView->General) (27 December , 2002) [permalink]
    NSRange zeroRange = { 0, 0 };
    [textView scrollRangeToVisible: zeroRange];

  • Converting string to an integer (NSString->General) (27 December , 2002) [permalink]
    NSString *string = ...;
    int value = [string intValue];

    Similarly, there is a floatValue and doubleValue NSString methods.

  • Enabling and Disabling menu items (NSMenu->General) (27 December , 2002) [permalink]
    Under most circumstances, it happens automatically: a menu item will be disabled if there is no object in the responder chain that handles the menu's action. If you want to override this behavior or extend it further, override validateMenuItem: and do something like this:
    - (BOOL) validateMenuItem: (id <NSMenuItem>) menuItem
    {
        BOOL result = YES;
    
        if ([menuItem action] == @selector(deleteNote:)) {
            if ([notes count] == 1) {
                result = NO; // can't delete the last note
            }
    
        } else if ([menuItem action] == @selector(gotoNote:)) {
            if ([notes count] == 1) {
                result = NO; // can't go to a different not if only one
            }
        }
    
        return (result);
    
    } // validateMenuItem
    

  • Running code before a menu action is sent (NSMenu->General) (22 December , 2002) [permalink]
    The NSMenuWillSendActionNotification is posted to the notification center before the action is invoked.

  • Disabling Chimera's url completion pop-up (Random->General) (19 December , 2002) [permalink]
    Add this to your ~/Library/Application Support/Chimera/Profiles/default/xyz.slt/prefs.js file:

    user_pref("browser.urlbar.autocomplete.enabled", false);

  • Dealing with directories with spaces in them (Unix->General) (13 December , 2002) [permalink]
    You can either escape the directory name with a space: % cd /Users/bork/Library/Screen\ Savers

    or you can surround it with quotes: % cd "/Users/bork/Library/Screen Savers"

    Note that tilde expansion (~/Library) is suppressed if you use the quotes.

  • Forcing validation of pending text field entries (NSTextView->General) (10 December , 2002) [permalink]
    [window makeFirstResponder: window]

  • Restricting typed in text to just digits (NSTextView->General) (10 December , 2002) [permalink]
    Create a subclass of NSNumberFormatter, add this method, and hook up the formatter to your text fields.
    - (BOOL) isPartialStringValid: (NSString **) partialStringPtr
            proposedSelectedRange: (NSRangePointer) proposedSelRangePtr
                   originalString: (NSString *) origString
            originalSelectedRange: (NSRange) origSelRange
                 errorDescription: (NSString **) error
    {
        NSCharacterSet *nonDigits;
        NSRange newStuff;
        NSString *newStuffString;
    
        nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
        newStuff = NSMakeRange(origSelRange.location,
                               proposedSelRangePtr->location
                               - origSelRange.location);
        newStuffString = [*partialStringPtr substringWithRange: newStuff];
    
        if ([newStuffString rangeOfCharacterFromSet: nonDigits
                options: NSLiteralSearch].location != NSNotFound) {
            *error = @"Input is not an integer";
            return (NO);
        } else {
            *error = nil;
            return (YES);
        }
    
    } // isPartialStringValid

  • Forwarding key events to another window (NSWindow->Random) (28 November , 2002) [permalink]
    To forward key events to another window, make subclass of NSWindow and override sendEvent:
    - (void) sendEvent: (NSEvent *) anEvent
    {
        if ([anEvent type] == NSKeyDown) {
            [someOtherWindow sendEvent: anEvent];
    
        } else {
            [super sendEvent: anEvent];
        }
    
    } // sendEvent
    
    It's up to you to figure out what "someOtherWindow" is, whether it's a delegate or an instance variable that holds the other window.

  • Keeping backup files of documents (NSDocument->General) (26 November , 2002) [permalink]
    override NSDocument's keepBackupFile:
    - (BOOL) keepBackupFile
    {
        return (YES);
    } // keepBackupFile
    
    This will do the tilde thing to the older version of the file.

  • Help! My Sheet won't go away (NSWindow->General) (21 November , 2002) [permalink]
    You may need to call [sheet close] in addition to your [NSApp endSheet: sheet returnCode:23]

  • Changing checkbox toggle state (NSControl->General) (19 November , 2002) [permalink]
    [myCheckbox setState: NSOffState]

    NSOnState also works.

  • Substring matching (NSString->General) (19 November , 2002) [permalink]
    NSRange range = [[string name] rangeOfString: otherString options: NSCaseInsensitiveSearch];

  • Converting from DOS to unix line terminators (Unix->General) (17 November , 2002) [permalink]
    % perl -pi -e 's/\r/\n/g' mealcsv.csv

  • Ignoring signals (gdb->General) (13 November , 2002) [permalink]
    (gdb) handle SIGTRAP nostop

    The signal still goes to your program. Another handy option is 'ignore' to prevent it coming to the program. Also there is 'print' to print a message go on.

  • using ssh (or CVS) without a password (Unix->General) (19 October , 2002) [permalink]
    Suppose you have two machines, the local one (your laptop) and the remote one (the honking big server located in Minneapolis that hosts gitdown.com) To ssh (or CVS) from the laptop to the server without needing a password, perform these steps:
    1. % ssh-keygen -t rsa
      (don't use a passphrase. Just hit return twice)

    2. % scp ~/.ssh/id_rsa.pub gitdown.com:

    3. On the remote machine (gitdown)

      % cat ~/id_rsa.pub >> ~/.ssh/authorized_keys

  • Use only spaces when indenting code (emacs->General) (08 October , 2002) [permalink]
    (setq indent-tabs-mode nil)

  • Showing the log comments between a set of revisions (CVS->General) (08 October , 2002) [permalink]
    % cvs log -r1.2:1.5 multiprocessing.txt

  • Putting an imac to sleep at the login box (Random->Random) (04 October , 2002) [permalink]
    Press the power button.

  • Seeing the parent process id in ps (Unix->General) (30 September, 2002) [permalink]
    Use the ppid option with the -o flag:

    % ps -axo user,pid,ppid,vsz,tt,state,start,time,command

  • Getting cvs update to build new directories (CVS->General) (27 September, 2002) [permalink]
    % cvs update -d [whatever]

  • Getting grep to return file names of matches rather than the actual match (Unix->General) (22 September, 2002) [permalink]
    Use the -l (dash ell) flag to grep. If a file contains the expression, the name of the file (rather than the matching line) is displayed. e.g. to open all the files that contain 'rzolf'

    % grep -l rzolf *.ham | xargs open

  • Darwin Website (Darwin->General) (18 September, 2002) [permalink]
    Since I can never remember this, it's at developer.apple.com/darwin.

  • Darwin's CVSROOT string (Darwin->CVS) (18 September, 2002) [permalink]
    for read-only checkouts:

    setenv CVSROOT :pserver:username@anoncvs.opensource.apple.com:/cvs/Darwin

  • Appending to the end of a textview (NSTextView->General) (18 September, 2002) [permalink]
        NSRange range;
        range = NSMakeRange ([[textView string] length], 0);
    
        [textView replaceCharactersInRange: range withString: string];
    And Peter Hosey provided a one-liner that may suit your needs better:
        [[[textView textStorage] mutableString] appendString: string];
    

  • Scrolling to the end of a textview (NSTextView->General) (18 September, 2002) [permalink]
        NSRange range;
        range = NSMakeRange ([[textView string] length], 0);
    
        [textView scrollRangeToVisible: range];
    I've heard that scrollRangeToVisible is O(N) for the length of the text. So be on the lookout if you have lots of text involved.

  • Fixing emacs C mode indenting (emacs->General) (28 August , 2002) [permalink]
    Here's a way to change the C indenting style to a major style, and override some of the pre-set values (like how emacs 21 changed the bsd indent level from 4 to 8. Gee thanks guys):
    (setq c-default-style "bsd"
          c-basic-offset 4)

  • Resetting shell mode's idea of the current working directory (emacs->General) (27 August , 2002) [permalink]
    Sometimes the shell mode will get confused as to what the current working directory is (like if you use aliases to move to a new directory, or if you use the conveniences like !$). M-x dirs will tell the shell buffer to figure out what the current working directory is.

  • Turning off command highlighting in shell mode (emacs->General) (27 August , 2002) [permalink]
    Emacs 21, which comes with Mac OS X 10.2, "helpfully" puts into bold the commands you execute in the shell. This drives me nuts, so I figured out how to turn it off. Add this to your .emacs file:

    (setq comint-highlight-input nil)

  • Turning off incremental-search highlighting (emacs->General) (27 August , 2002) [permalink]
    Emacs 21, which comes with Mac OS X 10.2, has highlighting enabled when doing incremental search (which drives me nuts). You can turn that off by setting this in your .emacs file:

    (setq search-highlight nil)

    You may also need to 
    (setq isearch-lazy-highlight nil)

    To turn off underlining of matching results. Only some OS X installs need this setting.

  • Running a screensaver as your desktop background (Screen Savers->Random) (26 August , 2002) [permalink]
    In a terminal, run

    % /System/Library/Frameworks/ScreenSaver.framework/Resources/ScreenSaverEngine.app/Contents/MacOS/ScreenSaverEngine -background &

    (all one command)

  • Dealing with the past (CVS->General) (05 August , 2002) [permalink]
    To check out the world as it was 3 days ago:

    % cvs checkout -D "3 days ago" blork

    Or via a date (month/day/year)

    % cvs checkout -D "10/17/2002" fnord

    or recently in time

    % cvs diff -D "1 hour ago" ook.blah

  • cd to directory with a space in its name (Unix->General) (17 July , 2002) [permalink]
    There's two ways to do it. The first is to backslash-escape the spaces:
    % cd /Users/bork/development/cool\ stuff/neat\ things

    The other is to use shell completion to put in the backslashes for you. In the above path, if you type
    % cd /Users/bork/development/cool[tab], it'll expand "cool stuff" for you.

  • Creating a RAM Disk (Unix->Random) (11 July , 2002) [permalink]
    % hdid ram://size where size is the size in bytes. the system will round that number up or down as it sees fit.

  • Getting curl to download a file (Unix->General) (03 July , 2002) [permalink]
    % curl -O http://borkware.com/quickies/files/fullscreensaver.tar.gz

  • Checking .nib and .pbproj files into CVS (CVS->General) (03 July , 2002) [permalink]
    You'll need to use the cvswrappers file provided in the devtools. The easiest thing to do is to copy it to your homedir and prepend a dot:

    % cp /Developer/Tools/cvswrappers ~/.cvswrappers

    You can also add the contents of that fike to your repository.

    .pbproj files aren't handled by the cvswrappers by default. You'll need to add a line like this:

    *.pbproj -k 'b' -f '/Developer/Tools/cvs-unwrap %s' -t '/Developer/Tools/cvs-wrap %s %s' -m 'COPY'

  • Backups on the cheap (Unix->General) (24 June , 2002) [permalink]
    I've been using hfstar for doing backups. I tar directory hierarchies to an external firewire drive from my TiBook (say my entire $HOME directory, plus the /Applicationsdirectory. There's probably other stuff that should be snarfed (like /Library), but I didn't on my last backup, and doing a restore from scratch seemed to work OK. Here's a quick outline of backing up to the external firewire drive called "Wikkit":
    • % sudo mkdir /Volumes/Wikkit/backup
    • % cd /Users
    • % sudo hfstar cf - bork | (cd /Volumes/Wikkit/backup; sudo hfstar xf -)
    The tar above is the standard push-pull tar. Both sides are run as root so that owner, group, and permissions are preserved for the files.

    To Restore:

    • % cd /Users
    • % sudo mv bork bork-orig
    • % cd /Volumes/Wikkit/backup
    • % sudo hfstar cf - bork | (cd /Users; sudo hfstar xf -)

    Some folks have had success with psync, but we haven't used it yet.

  • safely copying directories (Unix->General) (24 June , 2002) [permalink]
    cp -R is generally unsafe to copy directories with since it will copy through symbolic links rather than just copying the link (newer cp's have an -H flag that will work around this). The classic unix way of doing things like this is a push-pull tar:

    % tar cf - dir-name | (cd /destination-dir; tar xf -)

    In English: tar out through a pipe into a subshell that's changed directories, feeding that pipe into the tar extraction. If you run both sides of the pipeline as root (via sudo), the file owners and permissions will be preserved (which cp won't do)

  • wrong kind of tag compiler error. (Tools->Random) (12 June , 2002) [permalink]
    This one stumped me for awhile:
    BWNagType.h:23: `BWConcreteType' defined as wrong kind of tag

    In this particular case, I had a type I had declared with:
    @class BWConcreteType; and later on I had decided to turn it into an enum:
    typedef enum BWConcreteType { ... } BWConcreteType; 
    without removing the previous @class declaration. So be on the look out for conflicting types for the same symbol.

  • minimal tool (Random->General) (12 June , 2002) [permalink]
    I got tired of looking for this everytime I make a simple one-off tool without using Project Builder:
    #import 
    int main (int argc, char *argv[])
    {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
        [pool release];
    
    } // main
    

    And you can compile it on the command line with:

    cc -o test -framework Foundation file-name.m
    

  • Putting an image on a disk image's window (Random->General) (05 June , 2002) [permalink]
    To have snazzy disk images that have your logo or picture of your dog appear when you open them, do this:
    • run disk copy, make a new blank image. I'm calling mine "thingie"
    • copy image file to the mounted fake drive (logo.jpg)
    • open fake drive, choose Show View Options. Make sure you're just changing the current window, and not Everything.
    • Choose "picture", select the logo.jpg that's on the thingie drive
    • resize your window as appropriate
    • run this in the terminal to hide the logo.jpg file
      /Developer/Tools/SetFile -a V /Volumes/thingie/logo.jpg
    • eject thingie and re-mount it
    • you should now see your image, and no visible picture file icon

  • Fixing "no job control in this shell" (emacs->General) (26 May , 2002) [permalink]
    Emacs in Mac OS X 10.1.3 (and other versions) has an annoying habit of having broken shells when you do M-x shell. You get an error like "Inappropriate ioctl for device, no job control in this shell", which makes interrupting or backgrounding programs in shell mode impossible. Domo-kun gave me a one-line patch to the emacs source:
    #define DONT_REOPEN_PTY
    . Add that to darwin.h and build emacs. You can get the emacs source from the Darwin projects page. If you'd like a binary, drop us some mail.

  • Breaking on "Deallocation of a pointer not malloced" messages (Debugging->gdb) (25 May , 2002) [permalink]
    Put a breakpoint on fprintf

  • Add pgplsql support (Postgresql->General) (24 May , 2002) [permalink]
    % createlang plpgsql template1

  • Backing up a database (Postgresql->General) (24 May , 2002) [permalink]
    % pg_dump databasename > db.out

  • Logging into a remote database (Postgresql->General) (24 May , 2002) [permalink]
    On machine tower, dbname borkdb, user nettest
    % psql -h tower borkdb nettest

  • Restoring a Database (Postgresql->General) (24 May , 2002) [permalink]
    % psql -d databasename -f db.out

  • Adding a new machine alias via netinfo(e) (Unix->Administration) (06 May , 2002) [permalink]
    The NetInfo Manager utility is painfully slow. Here's how to add a machine via the command line. In this case adding the IP for a machine called "tower" (thanks to rzolf)
    # niutil -create . /machines/tower
    # niutil -createprop . /machines/tower ip_address 10.0.1.155
    # niutil niutil -createprop . /machines/tower serves ./local
    

  • Seeing functions and selectors (gdb->General) (05 May , 2002) [permalink]
    info selectors will show you all of the selectors in the application's symbol table. info functions will show you all of the functions. You can supply regular expressions to limit the output.

  • Reducing the size of a .dmg disk image (Random->General) (05 May , 2002) [permalink]
    DiskCopy won't let you create a disk image of less than 5 megabytes (a bit inconvenient for packaging a program that's 30K). Image->Convert Image will let you compress the image. As a side-effect of the compressed format, this makes the image read-only.

  • Creating a new database (Postgresql->General) (05 May , 2002) [permalink]
    % createdb database-name

  • Creating a new user (Postgresql->General) (05 May , 2002) [permalink]
    psql=# create user bork with password 'bork';

    You can also do this for a passwordless user: % crateuser bork

  • Logging in as a specific user (Postgresql->General) (05 May , 2002) [permalink]
    % psql database-name user-name

  • Manually starting the database (Postgresql->General) (05 May , 2002) [permalink]
    % pg_ctl -D /usr/local/pgsql/data -l /tmp/pgsql.log start

  • Seeing available databases (Postgresql->General) (05 May , 2002) [permalink]
    % psql -l
    (lower case Ell)

  • Setting file system attribute flags (Unix->Random) (01 May , 2002) [permalink]
    chflags in Mac OS X works like chattr over in Linux-land. So to make a file immutable (can't change it, even if you're the superuser), you can sudo chflags uchg file-name(s). To undo it, do sudo chflags nouchg file-name(s)

  • Handling double-clicks (NSTableView->General) (01 May , 2002) [permalink]
    Use NSTableView's -setDoubleAction: method, and supply it a standard IBAction-style method selector.

    You may need to also do -setTarget:. double-clicks get sent if the column isn't editable, so you may need to grab the column and do a -setEditable: NO on it.

  • Converting an event to view coordinates (NSView->General) (22 April , 2002) [permalink]
    NSPoint point = [self convertPoint: [event locationInWindow] fromView: nil];

  • How about a simple sample or two? (Screen Savers->General) (10 April , 2002) [permalink]
    There's SimpleSaver, a minimal 'bounce a line around the screen' screensaver. FullScreenSaver is the same thing, but it bounces the line around the user's desktop instead of just a black screen. Also check out Drip, a little more sophisticated (even has a configuration panel).

  • Grabbing the bits from the screen (Graphics->General) (10 April , 2002) [permalink]
    (Many thanks to Paul Sobolik for giving us this an updated and more reliable version)
    - (NSImage *) captureScreenImageWithFrame: (NSRect) frame
    {
        // Fetch a graphics port of the screen
    
        CGrafPtr screenPort = CreateNewPort ();
        Rect screenRect;
        GetPortBounds (screenPort, &screenRect);
    
        // Make a temporary window as a receptacle
    
        NSWindow *grabWindow = [[NSWindow alloc] initWithContentRect: frame
                                                  styleMask: NSBorderlessWindowMask
                                                  backing: NSBackingStoreRetained
                                                  defer: NO
                                                  screen: nil];
        CGrafPtr windowPort = GetWindowPort ([grabWindow windowRef]);
        Rect windowRect;
        GetPortBounds (windowPort, &windowRect);
        SetPort (windowPort);
    
        // Copy the screen to the temporary window
    
        CopyBits (GetPortBitMapForCopyBits(screenPort),
                  GetPortBitMapForCopyBits(windowPort),
                  &screenRect,
                  &windowRect,
                  srcCopy,
                  NULL);
    
        // Get the contents of the temporary window into an NSImage
    
        NSView *grabContentView = [grabWindow contentView];
    
        [grabContentView lockFocus];
        NSBitmapImageRep *screenRep;
        screenRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: frame];
        [grabContentView unlockFocus];
    
        NSImage *screenImage = [[NSImage alloc] initWithSize: frame.size];
        [screenImage addRepresentation: screenRep];
    
        // Clean up
        [grabWindow close];
        DisposePort(screenPort);
    
        return (screenImage);
    
    } // captureScreenImageWithFrame

  • Loading a string from a website (NSURL->General) (09 April , 2002) [permalink]
    (this will block until it loads)
        NSURL *url;
        NSData *data;
        NSString *blork;
        url = [NSURL URLWithString: @"http://borkware.com/hacks/random"];
        data = [url resourceDataUsingCache: NO];
        blork = [[NSString alloc] initWithData: data  encoding: NSASCIIStringEncoding];

  • Loading an image from a website (NSURL->General) (09 April , 2002) [permalink]
    (this will block until it loads)
        NSURL *url;
        NSData *data;
        NSImage *blork;
        url = [NSURL URLWithString: @"http://borkware.com/hacks/random-pic"];
        data = [url resourceDataUsingCache: NO];
        blork = [[NSImage alloc] initWithData: data];

  • Seeing the console.log without running Console.app (Unix->General) (08 April , 2002) [permalink]
    In a terminal or an emacs shell:
    % tail -f /var/tmp/console.log

  • I can't move or symlink a directory (Unix->Hacks) (08 April , 2002) [permalink]
    If you get the error
    mv: rename build/ to oopack: Is a directory
    
    when using mv or ln on the command line, that's a Darwin error. To correct the problem, remove the trailing slash from the directory name.

  • How do I set the name that's displayed in the preference panel? (Screen Savers->General) (08 April , 2002) [permalink]
    The "Product Name" setting on the Project Builder target has that. Change it by:
    1. open the Targets pane in Project Builder
    2. double-click on your target
    3. go to the Build Settings tab
    4. Edit your Product Name under General Settings

  • Where is my preference file? (Screen Savers->General) (08 April , 2002) [permalink]
    The screen saver preference file lives in the ~/Library/Preferences/ByHost directory. The name of the file is the name that you pass to defaultsForModuleWithName:, followed by .someBigNumber.plist.

    So, on my machine,

        userPrefs = [ScreenSaverDefaults defaultsForModuleWithName: @"BWDrip"];
    creates a file /Users/bork/Library/Preferences/ByHost/BWDrip.0003931024a6.plist

  • Populating a dictionary with predefined values (NSDictionary->General) (08 April , 2002) [permalink]
    dictionaryWithObjectsAndKeys is handy if you're setting up a defaults preference dictionary (or text attributes, or any dictionary) by hand:
        defaults = [NSDictionary dictionaryWithObjectsAndKeys:
                                 [NSNumber numberWithFloat: 25.0], @"density",
                                 [NSNumber numberWithFloat: 40.0], @"rate",
                                 nil];
    

  • Changing a file to -kb after it's been added (CVS->General) (08 April , 2002) [permalink]
    % cvs admin -kb filename

  • NSDebug.h (Debugging->General) (07 April , 2002) [permalink]
    Take a look at /System/Library/Frameworks/Foundation.framework/Headers/NSDebug.h. Lots of low-level unsupported APIs for mucking around with gory technical details.

  • Using "find" with multiple -name clauses (Unix->General) (04 April , 2002) [permalink]
    % find . \( -name "*.jpg" -or -name "*.gif" \) -exec do_something_with {} ;

  • Basics (NSTimer->General) (04 April , 2002) [permalink]
    - (void) handleTimer: (NSTimer *) timer
    {
        do some work here...
    } // handleTimer
    
    NSTimer *timer;
    
    timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
                     target: self
                     selector: @selector(handleTimer:)
                     userInfo: nil
                     repeats: YES];
    

  • Changing all *.oop files to *.ack (Unix->General) (02 April , 2002) [permalink]
    % ~/bin/rename.pl 's/.oop$/.ack/' *.oop

    To tack on an extension to all files, do something like % ~/bin/rename.pl 's/(.*)/$1.jpg/' *

  • Directory space consumption (Unix->General) (02 April , 2002) [permalink]
    To see how much disk space a directory consumes, use
    % du -sk dir_name

    To see how much each of a directory's contents consume, use
    % du -sk dir_name/* | sort -n to get a list ordered by size.

  • Doing something to a hierarchy of files (Unix->General) (02 April , 2002) [permalink]
    To do something to all of the html files in a directory (e.g. to grep something) 
    % cd directory
    % find . -name "*.h" -exec grep NSDoWhatIMean {} ; -print

    Don't forget the dot right after find, and the {} construct. Also make sure there's a space after the {} and ;

  • Getting a count from grep (Unix->General) (02 April , 2002) [permalink]
    To see how many times "fix me" occurs in the Objective-C files in the current directory:
    % grep -c "fix me" *.m

  • Removing files with a leading "-" (Unix->General) (02 April , 2002) [permalink]
    % rm -- -i-am-a-bad-file

  • Replacing a string in a set of files (Unix->General) (02 April , 2002) [permalink]
    % perl -pi.bak -e 's/OLDSTRING/NEWSTRING/g' *.html
    This will leave "*.bak" files around of the original version, in case the replacement string didn't quite do what you wanted.

  • Restricting Find to only deal with files (not directories) (Unix->General) (02 April , 2002) [permalink]
    % find . -type f -name "*.html" -exec grep Spoon {} ; -print

  • Running a pipeline in sudo (Unix->General) (02 April , 2002) [permalink]
    % sudo sh -c "tar cf - * | (cd /mirror4/web; tar xf -)"

  • Using Image Magick to scale an image proportionally (Unix->General) (02 April , 2002) [permalink]
    % find . -name "*.jpg" -exec convert -verbose -geometry 150x150 {} {} ;
    This converts the files in-place, so have a backup. Even though the geometry is specified as 150x150, that just means make the image no larger than 150 in either direction.

  • Using ImageMagick to get the dimensions of a file (Unix->General) (02 April , 2002) [permalink]
    % identify filename.jpg

    If you want to be studly, you can use -format to tailor the output

    % identify -format "insert into bw_graphics values (generate_primary_key(), '/images/llamas/%f', %w, %h);" *.jpg
    generates a sql insert statement for each image.

  • Building projects from the command line (Project Builder->General) (02 April , 2002) [permalink]
    Look at xcodebuild. We've got a rant about cocoa development in emacs, which includes a discussion of pbxbuild, the predecessor to xcodebuild. Some of the arguments have changed over the years. I usually run it like:
    % xcodebuild -configuration "Debug" -target "My Groovy App"
    
    If you have one target, or have a default target, you can leave out the -target argument.

  • Enabling core files (Debugging->General) (02 April , 2002) [permalink]
    Core files are handy to have around if your program crashes with a SEGV, bus error, or if it raises an abort(). You can dig into the core file with gdb There are two ways to enable core files:
    • in your C shell do
      % limit coredumpsize unlimited
      (you can put this into your .cshrc. I don't know what to do for bash)

    • Or in your program do
      struct rlimit corelimit = { RLIM_INFINITY, RLIM_INFINITY };
      setrlimit (RLIMIT_CORE, &corelimit);
       You may need to also add
      #include <sys/types.h>
      #include <sys/time.h>
      #include <sys/resource.h>

    Core files seem to be getting dumped into /cores, rather than the directory the program was run from.

  • Get a stack trace of all threads (Debugging->gdb) (02 April , 2002) [permalink]
    (gdb) thread apply all where

  • Setting a breakpoint before shared libraries are loaded (Debugging->gdb) (02 April , 2002) [permalink]
    Need to set a breakpoint, say on a Cocoa library function, or something in a shared library you're loading later? Set a "future breakpoint":
    (gdb) fb -[NSTextView drawRect:]

  • Disabling control-Z from backgrounding emacs (emacs->General) (02 April , 2002) [permalink]
    I find emacs' control-Z behavior to be pretty annoying (it backgrounds the program if you're in a shell, or hides the window if you're in X). Add this to your .emacs file:
    (global-set-key "C-Z" nil)

  • Toggling read-only mode in a buffer (emacs->General) (02 April , 2002) [permalink]
    C-X C-Q

  • Using carriage returns in query-replace / replace-string (emacs->General) (02 April , 2002) [permalink]
    Use C-Q C-J (control-Q control-J) each time you want to include a carriage return. e.g. to double-space everything

    M-x replace-string RET C-Q C-J RET C-Q C-J C-Q C-J RET

    Or to put "bloogie " at the beginning of every line

    M-x replace-string RET C-Q C-J RET C-Q C-J b l o o g i e SPACE RET

  • I want my window's background to be yellow (NSWindow->Hacks) (02 April , 2002) [permalink]
    Why you'd want to do that, I don't know, but someone asked me how to turn the window background yellow. Since the window has a contentView NSView in it, this adds a category on it that draws the background with a transparent yellow. You also get the pinstripe effects. Just put this code anywhere.
    @implementation NSView (BWYellowView)
    
    - (void) drawRect: (NSRect) rect
    {
        NSColor *transparentYellow;
    
        rect = [self bounds];
    
        transparentYellow = [NSColor colorWithCalibratedRed: 1.0
                                     green: 1.0
                                     blue: 0.0
                                     alpha: 0.333];
        [transparentYellow set];
        [NSBezierPath fillRect: rect];
    
    } // rect
    
    @end // BWYellowView
    
    I have no idea how you colorize the titlebar.

  • Becoming firstResponder if you don't have an editable cell (NSView->Hacks) (02 April , 2002) [permalink]
    You make a custom view, add it to your window in Interface Builder, and you make it the first responder. When you run the program, your custom view is not the first responder, instead some lame-O textfield has snagged keyboard focus. To address this, override this undocumented method:
    - (BOOL) _hasEditableCell
    {
        return (YES);
    } // _hasEditableCell
    
    This workaround is necessary at least for Mac OS X 10.1.*.

  • Easy NSLogging of basic data structures (Random->General) (02 April , 2002) [permalink]
    NSString has a couple of convenience functions for print out basic structures like NSRect and NSSize:
    • NSStringFromRect (someNSRect);
    • NSStringFromPoint (someNSPoint);
    • NSStringFromSize (someNSSize);

  • Finding my resources (Screen Savers->General) (02 April , 2002) [permalink]
    To find resources (say an image) from within the screensaver, use NSBundle bundleForClass. So, to get atomsymbol.jpg you would do something like
           NSBundle *bundle;
           NSString *path;
    
           bundle = [NSBundle bundleForClass: [self class]];
           path = [bundle pathForResource: @"atomsymbol"  ofType: @"jpg"];
           image = [[NSImage alloc] initWithContentsOfFile: path];

  • Changing the default Project Builder projects (Xcode->General) (02 April , 2002) [permalink]
    Don't like something about the default project that Xcode gives you? Look in /Library/Application Support/Apple/Developer Tools/Project Templates/ and edit the projects there.

    (For Project Builder, go to /Developer/ProjectBuilder Extras/Project Templates/ and edit the projects there. The changes will take effect next time you create a new project.)

  • How do I add a new folder to my Files view? (Xcode->General) (02 April , 2002) [permalink]
    Select the folder you want the new folder to be a child of. Select Project->New Group. Give it a name. Note that the hierarchy of files in Xcode is a fantasy of the project, and doesn't necessarily reflect what's actually in the file system.

  • Treat warnings as errors (Xcode->General) (02 April , 2002) [permalink]
    In Xcode, there's a handy "Treat Warnings as Errors" checkbox. I usually use the search dealie with "werr" to find the setting.

    (In Project Builder, open the Targets tab, double-click the target, go to the "Build Settings" tab, scroll down to Build Settings, look for WARNING_CFLAGS. Edit that, and add-Werror to what's already there.)

  • Using Objective C++ (Xcode->General) (02 April , 2002) [permalink]
    name your source file blah.M (upper case M), or name your source file blah.mm (two lower case Ms). It's best to use .mm because of the case-insensitive (yet case-preserving) nature of HFS+

posted by Sunny's
prev 1 next