Press "Enter" to skip to content

Category: Mac

NSFileHandle permission errors

In a macOS programming project I have a command that allows the user to open a file containing some configuration options. This file is a property list, so the contents were being read using NSDictionary(contentsOf:); this method simply returns nil if an error occurs. I wanted to provide more details about the failure than simply “The file could not be read”, so I looked for a Foundation method that would throw an NSError. I settled on FileHandle(forReadingFrom:) and inserted the following code:

    do {
        _ = try FileHandle(forReadingFrom: url)
    }
    catch let error as NSError {
        let alert = NSAlert()
        alert.messageText = "An error occurred while reading the options file.".localized()
        alert.informativeText = error.localizedDescription
        alert.beginSheetModal(for: mainWindow) { (response) in
            if response == NSAlertSecondButtonReturn {
                OperationQueue.main.addOperation { self.resetOptions(nil) }
            }
        }
        return
    }

Then I set up a few test cases, including a file that was owned by another user (with no read permission). To my surprise, the error description implied that I was unable to write the file:

[application icon redacted]

…and while that’s also true, that’s certainly not the error I expected to get.

I looked at the error object in the debugger, and sure enough, the error code was 513 (NSFileWriteNoPermissionError) and not 257 (NSFileReadNoPermissionError). Weird.

Well, I know I’m trying to read the file, and I don’t want to confuse the user, so I changed the catch clause to handle this case:

    catch var error as NSError {
        if error.code == NSFileWriteNoPermissionError {
            error = NSError(domain: NSCocoaErrorDomain, code: NSFileReadNoPermissionError, userInfo: error.userInfo)
        }
        let alert = NSAlert()
        //...
        return
    }

…and that seemed to do nicely. But I can’t find any documentation on whether this is expected behavior or what I might be doing wrong.

Comments closed

AppKit bug in 10.12.2: NSTextField with tabs in text displays incorrectly

UPDATE: The bug described below is fixed in macOS 10.12.4 and the workaround described is no longer necessary (except for backward compatibility).

In a recent macOS project I have an NSTextField that contains text with tab characters in order to display a data table. (The text is an NSAttributedString to which I apply an NSParagraphStyle with its tabStops property set to an array containing a number of right-aligned NSTextTabs.)

The text field was drawn as intended (with the text aligned to the tab stops) before upgrading to 10.12.2. After upgraded, the text was no longer aligned to the tab stops, and when using monospacedDigitSystemFont there were cosmetic glitches displayed as well:

Under time pressure for a release, I implemented the workaround of replacing the NSTextField with an NSTextView. (I did this dynamically since it is not obvious how to create “bare” NSTextViews in Xcode’s Interface Builder.) Using an NSTextView I was able to get the data table to display as I had intended.

When writing up this bug (#29758498; Radar, Open Radar) I tried to create a simple test case that would illustrate the issue, but on my first try to recreate the problem from scratch, the issue didn’t appear. Puzzled, I copied the code and .xib file from my application into the test project, and was able to reproduce the issue.

By examining the text of the .xib files, I discovered that my newly created .xib file has a content view with wantsLayer=”YES”, and in this case the NSTextField works as intended under 10.12.2; but the .xib file from my application (which was created before Xcode 8 was released) did not have a layer set on the content view, and this did not work under 10.12.2 (although it had worked fine on 10.12.1 and earlier). Setting a layer on the application’s window’s content view (in the View Effects tab of the Assistant Editor in Xcode) was enough to fix the issue and make the table display as intended:

(Yes, bridge players, those point counts are bogus; my test program is generating random values to insert into the table.)

My wider questions are:

  1. What happened? We know there were a lot of graphic updates in 10.12.2, but it’s odd that the problem only occurs with the system font. I haven’t investigated whether the font file itself has changed.
  2. I can’t believe I’m the only person that’s run into this (although my usual googling produced no other hits). Is this really an uncommon case? Or is this a(nother) gap in Apple’s test suite?
  3. If Apple is expecting that the default case for content views is to have wantsLayer set, then it should certainly make this more widely known. I couldn’t find any references to this issue in the AppKit release notes.
2 Comments

VisualEffectPlayground in Swift

When searching for information on implementing vibrancy effects and NSVisualEffectView, developers often find references to the VisualEffectPlayground sample code presented by Apple at WWDC 2014. However, they soon quickly discover that Apple pulled the sample code from the Apple Developer site. Perhaps the application was thrown together for WWDC and didn’t meet the usual standard for Apple sample code; however, to date Apple has not seen fit to post any replacement. And so the search continues.

During my own search, I discovered that a Xamarin engineer named Oleg Demchenko had ported the sample code to Mono and posted it to the Xamarin samples site. In order to get a working sample application, I decided to port this code back to Swift and posted it to GitHub.

DISCLAIMER: I don’t know C# and I’m still learning Swift. Nevertheless, the resulting application appears to perform as expected (although I haven’t made an exhaustive test). I will certainly consider any pull requests.

1 Comment

Downloading Office 2011

What do you do when it turns out that your downloaded disk image of Microsoft Office 2011 for Mac is on the 3TB Seagate drive that failed last week, and you didn’t back it up because you thought all that was on it was archived TiVo recordings?

Turns Out™ TJ Luoma knows what to do. Thanks, TJ.

(Next time: recovering data from a 3TB Seagate drive…)

Update 2016-01-21: Also Turns Out™ that if you already have Office 2016 installed, you can log into your Office account and go to the Install page; there is a link that says “Install previous version”.  Clicking this will download a disk image file containing an Office 2011 installer.  (The creation date of this installer is November 20, 2015, and the contents appear to be version 14.5.9; the most recent update as of this writing is 14.6.0, so remember to run Check for Updates after installing.)

Comments closed

Updating the cover of the Swift iBook

Apple updated the cover of The Swift Programming Language to match the new book in the series, but deleting and redownloading the book within iBooks in OS X Mavericks didn’t update the cover — it continued to display the original cover.

The solution was to quit iBooks, delete the iBooks cache located at ~/Library/Containers/com.apple.iBooksX/Data/Library/Caches/com.apple.iBooksX, and restart iBooks.

You’re welcome, Internet.

5 Comments

Improved cwd restoration in tcsh

My previous post illustrating a technique for restoring the current working directory in Apple’s Terminal for tcsh users was discovered by Khoo Yit Phang, who suggested an improved version down in the comments. I’m reproducing it here for greater visibility:

if ("$?TERM_PROGRAM") then
  if ("$TERM_PROGRAM" == "Apple_Terminal") then
    alias cwdcmd '( set echo_style = both; echo -n "33]7;file://${host}${cwd:ags/ /%20/}a" )'
    cwdcmd
  endif
endif

Compared to my approach, it has two improvements: (1) by using cwdcmd (of which I was previously unaware) rather than precmd, it only runs when you actually change directories; and (2) by using a suitably configured echo, it avoids running an external command (printf is not built into tcsh, but is present in /usr/bin).

Thanks, Yit.

Update: Of course, with this technique you have to explicitly run the command once, to restore the working directory to the title bar for the first time when you start up. Fixed above.

Comments closed

Current working directory restoration in Mavericks Terminal with tcsh

In John Siracusa’s excellent review of OS X Mavericks, he (originally) mentioned that the Terminal application is able to restore the current working directory of open shells across launches.

However, this section has subsequently disappeared from the online version, perhaps for the reasons given below (update: see below). Try looking here for a cached version of the original; scroll down to page/slide number 94. Sorry, John. Please purchase the full review on the iBooks store or the Amazon Kindle store to support John’s work.

Of course I was excited to try this out as, in the course of my work as a software developer, I often have several shell windows open in specific directories. So I tried it, and it didn’t work. It turns out the built-in support supplied by Apple assumes that you’re using the bash shell, but as an old-timer I’m stuck on tcsh instead:

Well, that’s no good, I thought. So I looked in the supporting code’s implementation (/etc/bashrc), and figured out how to do the same thing in tcsh. Simply place the following in your .tcshrc file:

if ("$?TERM_PROGRAM") then
 if ("$TERM_PROGRAM" == "Apple_Terminal") then
  alias precmd 'printf "33]7;%sa" "file://$host$cwd:ags/ /%20/"'
 endif
endif

This uses the appropriate escape sequence to send the URL of the current working directory to the terminal before each command; Terminal detects this information and uses it to update the state of the window (including a proxy icon in the window’s title bar for the corresponding folder). It turns out that the key is doing it using precmd (tcsh’s equivalent of PROMPT_COMMAND), and not sending the sequence in the prompt string itself as one might think. (The outer if statement is necessary to avoid an error when remotely logging in, as with ssh. It has to be a separate statement because of the variable expansion rules in tcsh.)

I’ve notified John via Twitter, so perhaps he add restore this information back to his review. In any case, it’s documented here for future generations. Drop me a note below if you have any issues with it.

Update: It turns out John removed it because he discovered it was a feature in Mountain Lion as well, which had happened not to work on his machine:

If you listen to John’s podcasts, you’ll realize that makes sense: he wouldn’t let something not new in Mavericks stand in the Mavericks review. Regardless, I wasn’t aware of the feature before and it still wouldn’t have worked in tcsh, so this post is presumably still useful. (Note that I haven’t tried it on Mountain Lion, and I’ve already upgraded my working machines to Mavericks; I don’t know why this technique wouldn’t work on Mountain Lion, but use it at your own risk.)

Update 2: OK, so it turns out the feature was first implemented in Lion, and other people have already figured out how to port it to other shells; see here for an implementation in zsh, for example. How did I manage to not learn about this for the last two years? Oh, well…

5 Comments

OCPython, anyone?

As dynamic scripting languages become more widely used, many developers are interested in using them to write “native” Mac OS X software, rather than having to learn Objective-C (which, of course, is a dynamic language in its own right). And in fact it is often possible to do so, using Apple’s BridgeSupport to generate the necessary metadata. Apple explicitly supports bridges for Ruby (RubyCocoa) and Python (PyObjC).

Nevertheless, there is necessarily an impedance mismatch between the runtime models — when passing objects to Cocoa, the bridge must convert the object from the dynamic language’s runtime to an Objective-C object derived from NSObject, and vice versa. This introduces a certain amount of inefficiency, which is not normally a big problem, but it would be desirable to avoid it.

Now, over the last few months, I’ve seen a variety of projects to do this by using the Objective-C 2.0 runtime to implement the object model for the dynamic language. In other words, objects in the dynamic language are subclasses of NSObject and no conversion is necessary.

These range from the venerable F-Script, which is even closer to Smalltalk than Objective-C, to Tim Burks’ original language Nu, which uses a Lisp-like syntax. I believe I’ve seen a reference to a JavaScript implementation as well, but I can’t seem to find it now.

The project that seems to be getting the most buzz in the Mac community right now is MacRuby, a port of Ruby 1.9 done by the developer of RubyCocoa (who is also an Apple employee). There was even a article about it featured on the Apple developer site recently.

Conspicuous by its absence from this list is my preferred dynamic language Python. I would love to see an implementation of Python hosted on the Objective-C runtime. I’ve always felt Python’s language model was a good match for Cocoa (of course, PyObjC not only predates BridgeSupport but even Cocoa itself, going back to the days of NextStep), and I’m personally more familiar with it than Ruby or other dynamic languages. So it seems like a logical step to take.

This project couldn’t be called MacPython, because that name has already been used to denote the Mac port of Python. For now I’m calling it “OCPython”, but I’m certainly open to a cleverer name (especially if there’s one that can riff on IronPython; unfortunately the element most associated with Mac OS X is Carbon, which is entirely wrong for this project).

I’ve been thinking about which version of Python to use as a jumping-off point; originally I was leaning towards 2.5 because it’s the version shipped with Leopard, but now I’m persuaded by Bill Bumgarner’s comment to use 3.0 and take advantage of the revised, less crufty implementation. (This is based on the stated goal of the 3.0 development project; I haven’t actually looked at the source code yet.)

I wish I could say I’m prepared to get the project off the ground myself, but right now I’m between jobs, as they say, and given the current financial situation I’m actively looking for full-time employment and can’t dedicate much time to something that won’t bring in any revenue. (Of course, if anyone out there would like to fund development of OCPython, contact me immediately.)

6 Comments

Pirates! returns to the Mac

As noted here, Feral Interactive is bringing Sid Meier’s Pirates! back to the Mac. [Edit: updated game-specific link]

I was inspired by this news to send the following email to Feral:

I was excited to see the announcement of the latest version of Sid Meier’s Pirates! for the Mac. I was the developer of the Mac port of the original version of Pirates! when I worked at MicroProse Software in the 80’s, and it was fun to see the black-and-white screenshot from our version on your website. I look forward to playing Pirates! once again on my PowerMac and MacBook Pro in the near future.

I hope this leads to a successful line of “Legends” — I have always felt that there was money to be made by porting older successful versions of PC games for the growing Mac marketplace, and I’m pleased to see that Feral agrees with me. Good luck with your upcoming launch.

We’ll have to see how this works out. (I know my son would probably vote for Sid Meier’s Railroads! next, being a huge Thomas the Tank Engine fan.)

Comments closed

I have a bad feeling about this

Sometime when I wasn’t looking Apple posted the WWDC session schedule. I hope I’m wrong, but already I see the potential for some serious problems.

WWDC does not seem to have a big reputation for being well-run. I can’t speak to this personally with any great authority; I’ve only attended one previous conference, in 2006. I didn’t really know what to expect, and I was excited just to be there, but even still there were a few issues I noticed. That year the sessions on the newly-announced Objective-C 2.0 and garbage collection were scheduled in a room that clearly was too small for the amount of interest. I saw there was a problem and decided to bypass the sessions, even though I was interested, figuring I could read up on the material later.

Meanwhile, the session on application code signing had been put in Presidio, the largest room — which I interpreted as a sign of the importance of the topic to Apple — but there were well fewer than a hundred people there. So Apple’s track record on predicting attendance is suspect at best.

Now this year they’ve sold out the conference, so we know it’s going to be crowded, and we know many if not most of those people are there for the iPhone. Apple seems to have booked Presidio exclusively with the key iPhone sessions, which is wise, but I fear it won’t be enough. I imagine four or five hundred people lining up early Tuesday morning, parking themselves in Presidio, and staying there for three and a half days. People who try to come for a later session are going to be annoyed if they can’t get in — but if Apple tries to clear the room after each session, people will get really angry.

[In 2006 they apparently ended up “repeating” a few of the overcrowded sessions by replaying them on a video projector one evening. I didn’t go; if I remember correctly, that was Wednesday, the night of the Apple Design Awards and Stump the Experts, and I didn’t want to miss those. This time around I’d probably pass them up, though. For one thing, the former DTS engineer with whom I saw Stump the Experts, and who made it twice as much fun by filling in the back story for me, is probably not attending this year.]

As a would-be independent developer with interests in both desktop and iPhone software, I’m anxious about the scheduling. On the one hand, if the iPhone session fill up I can usually find other sessions of interest to me. On the other hand, the trip out to San Francisco from the East Coast is a big deal in both time and money, and it’s not clear when I’ll be able to do it again, so I’d like to take advantage of the iPhone sessions as much as possible, since they’re clearly of more immediate value. (After all, I’ve got my Hillegas third edition right here already.)

At least if I keep myself on Eastern Time I can show up early every morning and get in line. I’ll miss the evening socializing, but I’m pretty introverted and don’t know anyone in SF, so that’s not much of a loss for me.

I sure hope this works out…

Comments closed