- 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:
- select range
- M-x copy-to-register
- 1
Paste from register 1:
- M-x insert-register
- 1
View the contents of a register
- M-x view-register
- 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 useNSPredicate
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 onCGPostError
. - 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 toCFRelease
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 overridelayoutSubviews
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
TheshowingDeleteConfirmation
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 releasinguuid
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 rowNSIndexPath *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 like0x7fff5fbfeeb0: 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 anxsd: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 inhg 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);
produces2009-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 ablah
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
You can force otest to run a particular architecture with the arch command: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.
% 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 anls -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. usels -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. Useen0
(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 aroundLunchLaunch Services, use thelsregister
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 withCFArraySortValues
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 thatself
is the object's logical value, not the actual value of theself
pointer.NSOrderedAsending
ifself
<thing2
NSOrderedDescending
ifself
>thing2
NSOrderedSame
ifself
==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 usetranslate
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 runuuidgen
, for instance:C-U M-!
retuuidgen
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 like2007-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 tellgdb
to 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 invokegdb
(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 likeoop :-) 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 inhello 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 usetouch
. 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'scompile 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 assignbuffer
tocalloc(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.
- 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
. TheatIndex:
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'srf
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 controllerselection
, 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 theLANG
environment variable to been_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 doingscreen-r again
- Changing the 'screen' hotkey (Unix->Tools) (28 June , 2006) [permalink]
Runningemacs
inside ofscreen
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
intobackward-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 usewchar_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 gottenszone_error
to actually do anything. Try breaking onmalloc_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 includeusefulStuff.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 pluginAdd 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 symbolBWDebugLog
(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 gdbTools/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 onlibgmalloc
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 inFixMath.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. Theinstall_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 oropen
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 overrideobserveValueForKeyPath: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 anapplicationShouldTerminate:
message, you're likely to want to returnNSTerminateLater
so that you can first gracefully shut down the connection before quitting.There is a gotcha: returning
NSTerminateLater
stops the main runloop, so yourNSTimers
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 returnNSTerminateCancel
, 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 theNSCoding
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 thedidEndSelector
. 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'sdisabledControlTextColor
won't draw the text in the disabled color. You need to use thesecondarySelectedControlColor
, 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
TheNSKeyValueChangeKindKey
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 theNSKeyValueChangeOldKey
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 thewindow
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 yousetFrame:
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]
UsesetFrame: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 theGrowl.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 theregistrationDictionaryForGrowl
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 ofNSWindowController
:@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 inEnglish.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 namedLocalizable.strings
that lives in yourEnglish.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 ansvn 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 usessetValue:forKeyPath:
to stick the value back into the bound object.The bindings and path are ivars:
id selectionRectBinding; NSString *selectionRectKeyPath;
Inbind: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 overrideawakeFromInsert
:- (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"sPut 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 calledwhat
)
- 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 calledradius
- (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 thatself
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]
UsemutableSetValueForKey:
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 manipulateNSMutableSet *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 saysDon'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'senvironment
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 DungeonBorkventureFirst, 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()
orNSFullUserName()
.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 overrideflagsChanged: (NSEvent *) event
and 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 makesself
an observer of thesearchArrayController
. We'll get notified when theselectionIndexes
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]
- (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 theobserveValueForKeyPath:
method. Register your observer like this:[searchArrayController addObserver: self forKeyPath: @"selectionIndexes" options: NSKeyValueObservingOptionNew context: NULL];
So now self's observeValue method will get invoked whenselectionIndexes
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 forNSAlternateKeyMask
, 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 forNSDeleteCharacter
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
and in the) 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 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 viaencodeValueOfObjCType:
. 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:- make the new project
- replace MyDocument with the newDocument name (BWGraphDocument here):
perl -pi -e 's/MyDocument/BWGraphDocument/g' *.[hm] *.xcodeproj/* *.plist
- rename the document files:
mv MyDocument.h BWGraphDocument.h
mv MyDocument.m BWGraphDocument.m - rename the nib file:
mv MyDocument.nib BWGraphDocument.nib
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
). TheNSSearchPathDomainMask
is what domains to find things in. For instance for aNSLibraryDirectory
, aNSUserDomainMask
will give you the path to~/Library
,NSSystemDomainMask
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 likeNSMutableString *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 :- Make an IBOutlet in your controller to point to the NSObjectController
- Drag an NSObjectController into the nib
- Add the names of the properties you're going to be binding with
- in AppController's
awakeFromNib
method, do[objController setContent: self];
awakeFromNib
helps prevent a retain cycle which can lead to memory leaks. - Handling unknown keys with KVC (Bindings->General) (07 January , 2005) [permalink]
OverridevalueForUndefinedKey:
:- (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 anNSDictionary
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 toimagesController
, "Controller Key" would beselection
, and "Model Key Path would befullPath
.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.
- 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:- Move (not copy) the original to a backup name. This will preserve the timestamp:
% sudo mv rc rc-orig
- Copy the original to the usual name:
% sudo cp rc-orig rc
- make your edits:
% sudo vi rc
% 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)
- Move (not copy) the original to a backup name. This will preserve the timestamp:
- 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 calledstripper.pl
which removes everything that looks like an HTML / SGML / XML tag:
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.#!/usr/bin/perl while (<>) { $_ =~ s/<[^>]*>//gs; print $_; }
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 anNSImage
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 anNSPDFImageRep
. Avoid theNSEPSImageRep
since it makes a trip throughNSPDFImageRep
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 supportselect 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 theNSEventTrackingRunLoopMode
, such as you wanting to use anNSNotificationQueue
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]
- Create a "AppName Help" directory in your
English.lproj
. - 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. - 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 yourAppName Help
directory. - Add these to your Info.plist:
<key>CFBundleHelpBookFolder</key> <string>AppName Help</string> <key>CFBundleHelpBookName</key> <string>AppName Help</string>
- Build, run, and cross your fingers. If Help.app is already running, you may want to exit it.
- Create a "AppName Help" directory in your
- 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
withprompt
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 ofNSWindowController
's cascading, otherwise it'll honor your width and height, but not your origin. In your document'swindowControllerDidLoadNib
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:- 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
- 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
- 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) ... }
- Make an
- Command-line building from xcode (Xcode->General) (15 January , 2004) [permalink]
xcodebuild
is thepbxbuild
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 inmain.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, addText::~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 endarchive_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 forNSTableViewDropAbove
- (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 yourmouseDownInHeaderOfTableColumn
ordidClickTableColumn
: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 theSEL
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 usesNSView
'sviewWithTag:
to find it. - Converting .snd resource to aiff (NSSound->General) (03 October , 2003) [permalink]
Get SoundApp PPC (a classic App). ChooseFile->Convert
, set these attributes:- Format : AIFF
- Encoding : PCM
- Rate : 44100 Hz
- Bits : 16 bits
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 theNSColor
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 putstitle
into the current thread's autorelease pool, sotitle
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 differentNSFileHandle
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 multipleNSTasks
and a bunch ofNSPipes
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 openook~.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, likefileManager: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 useNSPropertyListImmutable
andNSPropertyListMutableContainersAndLeaves
- Saving property lists as XML (XML->General) (20 April , 2003) [permalink]
You can save any of the "property list" classes (NSDictionary
,NSArray
,NSNumber
,NSString
,NSData
) as XML like this:NSData *data; data = [NSPropertyListSerialization dataFromPropertyList: notes format: NSPropertyListXMLFormat_v1_0 errorDescription: nil];
Then write out the data usingNSFileManager
, 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 yourshared_buffers
in yourpostgresql.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 theshmmax
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 therandom()
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 frombw_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 defaultpg_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 inLocalizable.string
, yourNSLocalizedString()
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 executeM-x revert-bufer
or bind that to a key, or else use a trick by doingC-x C-v
which invokesfind-alternate-file
, but just so happens to have the current buffer name, so you just have to doC-x C-v RET
- Cheap profiling (Unix API->General) (28 December , 2002) [permalink]
You can usegettimeofday()
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
anddoubleValue
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, overridevalidateMenuItem:
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]
TheNSMenuWillSendActionNotification
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 ofNSNumberFormatter
, 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 ofNSWindow
and overridesendEvent
:- (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'skeepBackupFile
:- (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:% ssh-keygen -t rsa
(don't use a passphrase. Just hit return twice)% scp ~/.ssh/id_rsa.pub gitdown.com:
- 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 theppid
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 thatscrollRangeToVisible
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 thecvswrappers
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 -)
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 (newercp
's have an -H flag that will work around this). The classic unix way of doing things like this is a push-pulltar
:% 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 (whichcp
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 onfprintf
- 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 likechattr
over in Linux-land. So to make a file immutable (can't change it, even if you're the superuser), you cansudo chflags uchg file-name(s)
. To undo it, dosudo chflags nouchg file-name(s)
- Handling double-clicks (NSTableView->General) (01 May , 2002) [permalink]
UseNSTableView
'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 errormv: rename build/ to oopack: Is a directory
when usingmv
orln
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:- open the
Targets
pane in Project Builder - double-click on your target
- go to the
Build Settings
tab - Edit your
Product Name
underGeneral Settings
- open the
- 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 todefaultsForModuleWithName:
, 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 sqlinsert
statement for each image. - Building projects from the command line (Project Builder->General) (02 April , 2002) [permalink]
Look atxcodebuild
. We've got a rant about cocoa development in emacs, which includes a discussion ofpbxbuild
, the predecessor toxcodebuild
. 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 withgdb
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 forbash
) - Or in your program do
struct rlimit corelimit = { RLIM_INFINITY, RLIM_INFINITY };
You may need to also add
setrlimit (RLIMIT_CORE, &corelimit);
#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. - in your C shell do
- 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]
UseC-Q C-J
(control-Q control-J) each time you want to include a carriage return. e.g. to double-space everythingM-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 likeNSRect
andNSSize
: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 likeNSBundle *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. SelectProject->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 fileblah.M
(upper caseM
), or name your source fileblah.mm
(two lower caseM
s). It's best to use.mm
because of the case-insensitive (yet case-preserving) nature of HFS+