Pasteboard Op Hosed My Mac

Today, during lunch, I continued to work through Aaron Hillegass‘s book, Cocoa Programming for Mac OS X. I was finishing up the chapter on using the Pasteboard for cut & paste, and my sample app was working as it should. And on my shiny Mac Pro, it ran very fast, indeed.

Then I got to the “Challenge” section… The challenge was to have the app copy its data to the pasteboard in both text and PDF formats. I got this working in about 5 minutes; no sweat.

Then I got creative… In the “For the More Curious: Lazy Copying” section, he explained how to have an application tell the pasteboard that it could provide data in various formats, just like usual, but to only put the data on the pasteboard when specifically asked by another app. I thought to myself, “Self, you should implement that with the text + PDF copying you’ve already got working.” And so I did. I got the code written in just a few minutes, referring to the API docs for various help. I ran my app, and copied the data. So far, so good. Then I went into the Preview app, selected File>New From Clipboard… and that’s when things started going South. I got the spinning beach-ball on Preview, and never a window opening. I toggled back over to my app, and it, too, was spinning. I killed Preview and my app, but trying to restart my app resulted in the window showing up, but the spinning beach-ball, and nothing else.

At this point, I figured I had hosed something, so I killed off Xcode and tried to restart it. Same thing as with the others: menubar + spinning beach-ball. Now, I figured a reboot was going to be required. And so it was, but actually rebooting proved to be a problem. I started killing off all my apps and while some would actually quit, some wouldn’t. I tried killing them from Activity Monitor, which worked on some, but not others. I then went to the Apple menu and selected Restart… which eventually timed out trying to kill the running apps. I tried again, but it still wouldn’t restart. I killed some more apps, and tried restarting again, but no dice. I finally killed the power to the box and turned it back on.

If anyone is interested, here are the relevant pieces of code that were involved in this fiasco.

The class is called BigLetterView, and it’s a subclass of NSView. The first method to see is copy:

 	- (IBAction) copy: (id) sender 
	{
 	    NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
 	    [self declarePasteboardTypes: pasteboard];
  	    NSLog(@"Backing up data");
 	    [self backupDataForCopy];
 	    NSLog("@Backed up data");
  	    // [self writeStringToPasteboard: pasteboard];
 	    // [self writePdfToPasteboard: pasteboard];
 	} 	

Next is the method called from copy: that makes a copy of the data so that if the current values changes, a paste from another app will get the data as they were when the copy was invoked.

 	- (void) backupDataForCopy
 	{ 
	    backupString = [string copy];
 	    backupPdf = [self generatePdf];
 	} 	

Moving right along, we come to the method that is invoked when another app tries to paste our data from the pasteboard.

 	- (void) pasteboard: (NSPasteboard *) pasteboard provideDataForType: (NSString *) type 	{
 	    NSLog(@"Pasteboard requesting data of type: %@", type);
  	    if ([type isEqual: NSStringPboardType])
 	    {
 	        [self writeStringToPasteboard: pasteboard];
 	    } else if ([type isEqual: NSPDFPboardType])
 	    {
 	        [self writePdfToPasteboard: pasteboard];
 	    } else
 	    {
 	        NSBeep();
 	    }
 	} 	

And, finally, the two methods that write the data to the pasteboard when asked

 	- (void) writePdfToPasteboard: (NSPasteboard *) pasteboard 
	{
 	    // NSData *data = [self generatePdf];
     	    // [pasteboard setData: data forType: NSPDFPboardType];
 	    [pasteboard setData: backupPdf forType: NSPDFPboardType];
 	}

  	- (void) writeStringToPasteboard: (NSPasteboard *) pasteboard
 	{
 	    // copy data to the pasteboard
 	    [pasteboard setString: backupString forType: NSStringPboardType];
 	    // [pasteboard setString: string forType: NSStringPboardType]; 	} 	

The problem seems to be in pasteboard:provideDataForType:, though I can’t see what it is. When I hit Cmd-C, the copy works OK. When I switch to Preview and select File>New From Pasteboard is when everything locks up. What looks to be happening is that the pasteboard service (pbs) is getting hosed, and it’s considered a “critical service” by the OS (I read that in some OSX docs), so if it’s dead/dying other apps who try to contact it are locking up. Makes sense. I tried restarting pbs, but that didn’t seem to make a difference.

So, has anyone else fought with this situation? If so

  • Do you see a problem with the code snippets above?
  • How can you recover from hosing pbs?
  • Any other suggestions?
Advertisements