<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3346053520704872623</id><updated>2011-12-21T11:18:39.780-05:00</updated><category term='Adobe'/><category term='dmg'/><category term='threads'/><category term='java'/><category term='security'/><category term='C'/><category term='macros'/><category term='scm'/><category term='UI'/><category term='os x'/><category term='RAII'/><category term='Apple'/><category term='system calls'/><category term='cocoa'/><category term='C++'/><category term='Steve Jobs'/><category term='inheritance'/><category term='Flash'/><category term='git'/><category term='pita'/><category term='browser'/><category term='classes'/><category term='internet'/><category term='fail'/><category term='strings'/><category term='ipc'/><category term='core foundation'/><category term='authorization'/><title type='text'>QuantumCheese Code Quirks</title><subtitle type='html'>Problems, solutions, and strange situations in programming.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>24</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-1827574058274221728</id><published>2011-12-21T11:08:00.003-05:00</published><updated>2011-12-21T11:18:39.791-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Developments</title><content type='html'>Since my previous post, I have changed employers twice.  First to SMSI, but I didn't feel like I was doing meaningful work there.  I now work for Amazon on the Kindle Team.  I find that I prefer C++ and Objective-C to Java, but I am willing to admit that it could be due to lack of understanding of the inheritance model.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-1827574058274221728?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/1827574058274221728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2011/12/developments.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/1827574058274221728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/1827574058274221728'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2011/12/developments.html' title='Developments'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-5971346446212721066</id><published>2011-06-16T09:59:00.003-04:00</published><updated>2011-06-16T10:02:54.105-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='fail'/><title type='text'>Unbundled Info.plist on 10.5 Leopard</title><content type='html'>We recently added a non-privileged, unbundled (stand-alone) helper tool to our main application bundle.  At first it showed up in the Dock, but then we added &lt;key&gt;LSUIElement&lt;/key&gt;&lt;true /&gt; to that application's Info.plist.  Naturally, we embed that plist with &lt;code&gt;-sectcreate __TEXT __info_plist Info_plist_file&lt;/code&gt;.&lt;br /&gt;However, 10.5 did not respect this setting.  It insisted on displaying a duplicate Dock tile for the main app -- same name and icon.  We tried several variations, but the only thing we found that works on 10.5 is to make the helper application a Cocoa app bundle and include its Info.plist there.  Only then is the LSUIElement preference respected.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-5971346446212721066?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/5971346446212721066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2011/06/unbundled-infoplist-on-105-leopard.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/5971346446212721066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/5971346446212721066'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2011/06/unbundled-infoplist-on-105-leopard.html' title='Unbundled Info.plist on 10.5 Leopard'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-2228970976112424857</id><published>2011-01-03T11:14:00.002-05:00</published><updated>2011-01-03T11:25:53.555-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='dmg'/><category scheme='http://www.blogger.com/atom/ns#' term='pita'/><title type='text'>App Distribution</title><content type='html'>Everyone wants to have users download a small .dmg file from their website.  Opening the dmg pops up a window showing a pretty background, the application's icon, and an alias file to the /Applications directory.&lt;br /&gt;&lt;br /&gt;Finder in 10.6 creates non-backward compatible .DS_Store files, so to get the positioning and background image, you need to create a dummy dmg by hand on 10.5, copy its .DS_Store, and save it for copying into your production dmg.&lt;br /&gt;&lt;br /&gt;No-one wants their dmg to have a .Trashes directory, and no-one wants the mounted image to have free space -- it's just wasteful, and it feels unprofessional.  The key to creating just such a dmg is to populate a local directory with everything you want in your dmg, use hdituil to makehybrid from it, and then convert to the desired format (probably UDBZ format with -imagekey bzip2-level=9 for maximum compression).&lt;br /&gt;&lt;br /&gt;If you have an SLA that you want to display, you can unflatten, add the rtf SLAs using Rainer Brockerhoff's &lt;a href="http://brockerhoff.net/blog/2010/02/10/addlicense-tool/"&gt;AddLicense tool&lt;/a&gt;, and then flatten the dmg again.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-2228970976112424857?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/2228970976112424857/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2011/01/app-distribution.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/2228970976112424857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/2228970976112424857'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2011/01/app-distribution.html' title='App Distribution'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-446950924858181110</id><published>2010-09-02T13:46:00.001-04:00</published><updated>2010-09-02T13:48:14.678-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='browser'/><title type='text'>Google Chrome</title><content type='html'>Until now, I have been using Google Chrome web browser.  I manually removed its Keystone updater launchd jobs and  executable.  However, I stopped using it today because it stopped showing me the uri of the webpage I was viewing.  This is unforgiveable.&lt;br /&gt;The browser is not supposed to guess that there is some information I don't want.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-446950924858181110?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/446950924858181110/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2010/09/google-chrome.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/446950924858181110'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/446950924858181110'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2010/09/google-chrome.html' title='Google Chrome'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-2340280407458273650</id><published>2010-07-29T16:26:00.007-04:00</published><updated>2011-01-03T11:26:47.233-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='authorization'/><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='system calls'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>Installing a Helper Tool</title><content type='html'>If your application does something with/to files that the user wouldn't normally have access to, you can use IPC (inter-process communication) with an Elevated Helper Tool.  But how do you install the Helper Tool?&lt;br /&gt;&lt;br /&gt;Prior to OS X 10.6, you would have to use a Helper Tool Installer, which you would have to launch using AuthorizationExecuteWithPrivileges(...).  The (authorized) Installer would also have to install a launchd plist and register the plist using launchctl.&lt;br /&gt;&lt;br /&gt;On 10.6 "Snow Leopard", Apple has made this process easier with the Service Management APIs.  There is one API now, SMJobBless, that takes your authorization and the name of the helper tool, and installs it.  Here are some of the details of using it.&lt;br /&gt;&lt;br /&gt;Both the application and the Helper Tool must be code signed.  It isn't necessarily important who is the CA.&lt;br /&gt;&lt;br /&gt;The Helper Tool must reside inside of your application bundle in the Contents/Library/LaunchServices directory.  The name of the HelperTool executable file MUST be its launchd Label.  This is usually a reverse-DNS label such as com.QuantumCheese.MyApp.HelperTool .&lt;br /&gt;&lt;br /&gt;Furthermore, SMJobBless requires two custom sections in the __TEXT segment of your executable.  The first of these is the info plist.  This is a normal Info.plist file, customized for your Helper Tool.  It must contain an array SMAuthorizedClients of code signing requirements for authorized clients.  It is also a good idea to have a version string (the key is CFBundleVersion) and a bundle name (key CFBundleIdentifier) (probably the Label).&lt;br /&gt;The second is the launchd plist.  This is the same plist you would have written from the Installer executable; it ends up in /Library/LaunchDaemons.  See man (5) launchd.plist for information on this file; it must include the Label, and it should not include Program or ProgramArguments keys (they will be ignored and replaced).&lt;br /&gt;&lt;br /&gt;In the Xcode project settings for your helper tool's target, add Other Linker Flags of&lt;br /&gt; -sectcreate __TEXT __info_plist /path/to/your/daemon's/info.plist&lt;br /&gt;and&lt;br /&gt; -sectcreate __TEXT __launchd_plist /path/to/your/daemon's/launchd.plist&lt;br /&gt;Note that these two lines will be split into eight lines; make sure that each 4 stay together.&lt;br /&gt;&lt;br /&gt;The documentation for SMJobBless says that the only domain currently supported is kSMDomainSystemLaunchd.  Therefore, SMJobBless will take your Helper Tool, extract its __launchd_plist to /Library/LaunchDaemons/reverse-DNS-HelperTool.plist, and copy the Helper Tool to /Library/PrivilegedHelperTools/reverse-DNS-HelperTool.  It automatically version checks, and the API returns true on successful upgrade or if the tool is already installed.&lt;br /&gt;&lt;br /&gt;Experiments indicate that it will return true even if a newer version of the Helper Tool is installed.  Therefore, if your IPC demands that your bundled version exactly matches the installed version, you will still need to use the Helper Tool Installer to downgrade.&lt;br /&gt;&lt;br /&gt;Even though it is tempting, I recommend against putting an additional copy of the executable into the Contents/MacOSX folder.  While doing so would let you use the CFBundleCopyAuxiliaryExecutableURL API to create a URL to the helper executable, it increases the size of your bundle, which is a bigger problem than finagling the helper executable's URL on 10.5.&lt;br /&gt;Instead, I recommend appending the Contents/Library/LaunchServices/HelperTool path to the URL obtained from CFBundleCopyBundleURL(CFBundleGetMainbundle()).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-2340280407458273650?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/2340280407458273650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2010/07/installing-helper-tool.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/2340280407458273650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/2340280407458273650'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2010/07/installing-helper-tool.html' title='Installing a Helper Tool'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-8527690356897152731</id><published>2010-06-02T11:53:00.002-04:00</published><updated>2010-06-02T11:57:50.787-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='fail'/><category scheme='http://www.blogger.com/atom/ns#' term='macros'/><title type='text'>Ways to Bork Your Code</title><content type='html'>Maybe I'll make this a series of posts: ways to screw up, big time.&lt;br /&gt;&lt;br /&gt;Preprocessor macros are very handy, but very easy to abuse.  One day in college, a few of us sat around trying to think of devious macros we could include in our projects that would mess up other contributors' code.&lt;br /&gt;We tried &lt;code&gt;#define 1 (-12)&lt;/code&gt;, but it wouldn't compile.&lt;br /&gt;We did succeed in &lt;code&gt;#define main foo&lt;/code&gt; to eliminate the main function, but my personal favorite takes two lines:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#define if while&lt;br /&gt;#define else&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And of course, to be a good hygienic programmer, you'd want to include the accompanying #undefs.  Please never use this.&lt;br /&gt;I can just imagine some confused code successor looking at the file and asking, "Why does this file end with #undef if? Uhh....."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-8527690356897152731?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/8527690356897152731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2010/06/ways-to-bork-your-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/8527690356897152731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/8527690356897152731'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2010/06/ways-to-bork-your-code.html' title='Ways to Bork Your Code'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-4460313862540614420</id><published>2010-05-30T16:53:00.002-04:00</published><updated>2010-05-30T17:29:27.654-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fail'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='UI'/><title type='text'>NSMenu popup location</title><content type='html'>NSMenu has a class method popUpContextMenu:withEvent:forView:, which I initially thought was the only way to cause a menu to pop-up where I wanted.  In order to give it a useful event, I took the event I had and created a new one from it, with a different mouse location, to try to trick the menu's position.  The goal is that the menu should normally appear under the control, with the left of the menu aligned to the left of the control.  If there isn't enough room under the control, the menu should appear above the control and not obscure it from view.  Similarly, if there isn't enough space to the right of the control for the entire menu to display, the menu should right-align to the control.&lt;br /&gt;I had gotten the above/below positioning sorted out using the NSMenuDelegate method confinementRectForMenu:onScreen:, but I could not get the left/right alignment switch to work.  If I would set the menu rect's origin to the left of the control, the upper-right of the menu would be there; and if I set it to the right of the control, the menu's upper-left would be there.&lt;br /&gt;I put the menu to the left of the control entirely and then moved the x field of the origin over by the width of the menu.  No good.&lt;br /&gt;I tried moving it over incrementally over several test runs.  It eventually became clear that I could not move the x coordinate of the menu's origin past 5/6 of the width of the control without the menu aligning its left to the left of the control.&lt;br /&gt;&lt;br /&gt;I then discovered that NSMenu has an instance method popUpMenuPositioningItem:atLocation:inView:.  This method had much better documentation, saying that I could pass nil for the item and the view, and then I could control the upper-left corner of the menu rect, and it would pop-up unattached to any other window.  I tried this out, and it worked, with less code (no longer needed to fake an NSEvent).&lt;br /&gt;I went back and used a nil view for the class method, and this also worked.&lt;br /&gt;&lt;br /&gt;My recommendation is to use the class method, since it provides the flexibility to position an arbitrary item in the menu or the entire menu at a certain point, and it has much better documentation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-4460313862540614420?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/4460313862540614420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2010/05/nsmenu-popup-location.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/4460313862540614420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/4460313862540614420'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2010/05/nsmenu-popup-location.html' title='NSMenu popup location'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-7044069539598404742</id><published>2010-04-29T10:45:00.006-04:00</published><updated>2010-04-29T10:58:47.044-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Steve Jobs'/><category scheme='http://www.blogger.com/atom/ns#' term='Adobe'/><category scheme='http://www.blogger.com/atom/ns#' term='Flash'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Apple and Adobe</title><content type='html'>My response to Steve Jobs' mostly well-written &lt;a href="http://www.apple.com/hotnews/thoughts-on-flash/"&gt;reasons for not allowing Flash on his mobile devices&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Jobs is spot-on that Flash is a closed, proprietary system.  It renders video (and other content) in software, not hardware; he claims that all mobile devices decode H.264 in hardware, and can play 10 hours of H.264 video content vs. 5 hours of software-decoded video.  I haven't tested his claim, but specialized hardware seems like it ought to do the job better.&lt;br /&gt;&lt;br /&gt;The part that really bothers me is where he attacks Adobe's iPhone programming interface: "We know from painful experience that letting a third party layer of software come between the platform and the developer ultimately results in sub-standard apps and hinders the enhancement and progress of the platform."&lt;br /&gt;The "progress of the platform" is nonsense.  It is up to the developers to use whatever tools they chose to create the products they desire.  It is not relevant to Apple what methods we, the developers, use to create our content.&lt;br /&gt;&lt;br /&gt;Furthermore, Steve Jobs has no right to complain that Flash is a closed system when his App Store is even more restrictive.  It would be better to have an Open app store and allow developers to use whatever tools we want!&lt;br /&gt;&lt;br /&gt;Jobs complains that "[t]he third party may not adopt enhancements from one platform unless they are available on all of their supported platforms. Hence developers only have access to the lowest common denominator set of features. Again, we cannot accept an outcome where developers are blocked from using our innovations and enhancements because they are not available on our competitor’s platforms."&lt;br /&gt;Again, this is better than Apple's practice of changing the APIs out from under developers.  Their attitude is one of "We're so very glad that you used our APIs, but we've deprecated them all, so you'll have to rewrite your code, at least to have dynamic OS-testing," but they say it differently (from the article): "We want to continually enhance the platform so developers can create even more amazing, powerful, fun and useful applications. "&lt;br /&gt;This is a terrible methodology, and it's a terrible way to treat programmers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-7044069539598404742?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/7044069539598404742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2010/04/apple-and-adobe.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/7044069539598404742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/7044069539598404742'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2010/04/apple-and-adobe.html' title='Apple and Adobe'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-1418089584585955183</id><published>2010-04-14T18:09:00.006-04:00</published><updated>2011-01-03T11:32:32.007-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='dmg'/><category scheme='http://www.blogger.com/atom/ns#' term='pita'/><title type='text'>Creating a DMG with an icon and background image</title><content type='html'>[Posted with permission from my client.]&lt;br /&gt;&lt;br /&gt;Our Release mode build is designed to package up the final app bundle into a dmg.  We wanted to make a nice user experience, similar to the images of Google Chrome and Firefox, so we added an alias to /Applications and set the alias' name to " ".&lt;br /&gt;We use an applescript to set the position and size of the icons in icon view, and also to set the background image.  However, we could not figure out how to set the icon for the mounted volume in Finder's sidebar.  I knew that it involed .VolumeIcon.icns, but that was insufficient.&lt;br /&gt;After much searching, we realized that we had to set extended Finder attributes for the volume's root directory, but couldn't figure out how to do so from the shell / applescript.  Finally, we found xattr, but there was no documentation to indicate what names or attributes to use.  However, Google Chrome and Firefox both had the same set of 32 4-byte hex flags, so we simply copied them.&lt;br /&gt;&lt;br /&gt;Solution: with read/write dmg mounted (and a disk name of VOLUME_NAME), use the following command from the Terminal (or shell script):&lt;br /&gt;&lt;code&gt;&lt;br /&gt;xattr -wx com.apple.FinderInfo 00000000000000000400FFFFFFFF000000000000000000000000000000000000 "/Volumes/${VOLUME_NAME}"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;UPDATE:&lt;br /&gt;There is a much more intuitive interface: &lt;code&gt;SetFile -a C "/Volumes/${VOLUME_NAME}"&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-1418089584585955183?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/1418089584585955183/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2010/04/creating-dmg-with-icon-and-background.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/1418089584585955183'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/1418089584585955183'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2010/04/creating-dmg-with-icon-and-background.html' title='Creating a DMG with an icon and background image'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-2672141772341821922</id><published>2010-02-24T14:39:00.002-05:00</published><updated>2010-02-24T14:58:40.540-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fail'/><category scheme='http://www.blogger.com/atom/ns#' term='internet'/><title type='text'>Specifying a port on IPv6</title><content type='html'>My colleagues at Javacool Software got a feature request today for an existing product, that it should run on a custom port, presumably due to the client's unusual network setup.&lt;br /&gt;While doing that, we decided that it makes sense to support this feature for IPv6 as well.  However, it turns out that specifying a port on IPv6 is much more annoying that on v4.  In v4, the format is like so: dot-separated-IP:port.  In v6, like so:   [colon-separated-IP]:port.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-2672141772341821922?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/2672141772341821922/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2010/02/specifying-port-on-ipv6.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/2672141772341821922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/2672141772341821922'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2010/02/specifying-port-on-ipv6.html' title='Specifying a port on IPv6'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-4086696985450917344</id><published>2010-02-12T10:04:00.002-05:00</published><updated>2010-02-12T10:07:06.375-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scm'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Source Control</title><content type='html'>Until now, the CFRaii library has been available from &lt;a href="http://code.quantumcheese.com"&gt;my website&lt;/a&gt;.  Now it is also &lt;a href="http://github.com/quantumcheese/CFRaii.git"&gt;publicly available&lt;/a&gt; through github.  This is a trial for me, to see if I like git and github.  I'll let you know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-4086696985450917344?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/4086696985450917344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2010/02/source-control.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/4086696985450917344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/4086696985450917344'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2010/02/source-control.html' title='Source Control'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-1250446132285265715</id><published>2010-01-27T20:57:00.003-05:00</published><updated>2010-01-27T21:04:47.577-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fail'/><category scheme='http://www.blogger.com/atom/ns#' term='threads'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>NSThread</title><content type='html'>The project I'm working on uses threads.  Like a good Cocoa app, the main thread is in charge of the GUI, and the worker threads run in the background so that we don't pinwheel.&lt;br /&gt;In order to know when the thread has finished its work, we registered for notification:&lt;br /&gt;&lt;code&gt;&lt;br /&gt; [[NSNotificationCenter defaultCenter] addObserver:self&lt;br /&gt;            selector:aSel&lt;br /&gt;             name:NSThreadWillExitNotification&lt;br /&gt;              object:thread];&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;and in the aSel method, use ivars to update an NSTableView's dataSource.&lt;br /&gt;&lt;br /&gt;We had a really pesky race condition that, after two days, we realized was caused by aSel running in the same worker thread!  It turns out that this is in the documentation, that notifications are served to the same thread that posts them.  However, this is a fairly useless implementation decision.&lt;br /&gt;&lt;br /&gt;Our workaround is not to register for the notification, but rather to have the thread performSelectorOnMainThread:withObject:waitUntilDone: at the end of its execution.  There is still a problem that we'd like to release the thread at that point, but we don't know what will happen if we try that!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-1250446132285265715?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/1250446132285265715/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2010/01/nsthread.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/1250446132285265715'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/1250446132285265715'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2010/01/nsthread.html' title='NSThread'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-6944473683631833499</id><published>2010-01-08T09:33:00.003-05:00</published><updated>2010-08-30T15:35:12.313-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Apple, part II</title><content type='html'>The same day I received the rejection email from Apple, a different Apple recruiter contacted me on LinkedIn and asked me if I would be interested in a job at Apple.  I wanted to see where it would go, so I said sure, tell me about the job.  He described a position with the security testing team for all Apple products, but only very broadly.  When I asked some detailed questions, he couldn't answer them, so he offered to set up a phone call with the team leader.&lt;br /&gt;About 1.5 weeks after being contacted on LinkedIn, I got a call from the team leader.  He described the position, and it sounded like something I'd enjoy, so I asked him how to apply for it; should I send a resume, etc.  He said he had something like a resume in front of him (which I assume the recruiter copied from LinkedIn), and that I didn't have the experience or background they wanted, unless there was something I'd left off my resume.&lt;br /&gt;I asked him why, if he had already decided that I didn't have the background he wanted, did he call me?  He told me that he'd called me because the recruited had asked him to, because the recruiter couldn't answer my questions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-6944473683631833499?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/6944473683631833499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2010/01/apple-part-ii.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/6944473683631833499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/6944473683631833499'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2010/01/apple-part-ii.html' title='Apple, part II'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-7887418174262251793</id><published>2009-12-02T08:17:00.003-05:00</published><updated>2010-01-20T09:29:15.633-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Apple, part I</title><content type='html'>In June of 2009, I applied to work at Apple.  A few weeks later, I got a call from an Apple recruiter, and we scheduled a first-round phone interview.  I passed that one, and he called to schedule a second-round phone interview.  I passed that one, too, and he called to schedule an in-person third-round interview.&lt;br /&gt;By now it was mid-August.  I took a day off of work to interview with 6-7 different Apple engineers, each for 45 minutes.  I talked with them, showed them what I knew and what I could do in terms of coding and theory.  The group leader told me I'd hear back by the end of the week.  I thanked them, and went home.&lt;br /&gt;I made a mistake, in that I didn't immediately send a "thank you" email; I waited a few days to do so.&lt;br /&gt;The week ended, and I hadn't heard anything.  I thought perhaps I misheard, and he'd said the end of the following week.  Still nothing.  No phone call, no email.&lt;br /&gt;The next week, now 2.5 weeks after my interview, I emailed to ask if there was anything I could give them -- references, or further background, or anything -- to help them decide.  The following was the entirely of the response I received, without the names:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Sorry [me].   Unfortunately, the team decided to pass on your candidacy.&lt;br /&gt;&lt;br /&gt;[recruiter]&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-7887418174262251793?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/7887418174262251793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2009/12/apple-part-i.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/7887418174262251793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/7887418174262251793'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2009/12/apple-part-i.html' title='Apple, part I'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-6523446144958179376</id><published>2009-07-31T11:34:00.005-04:00</published><updated>2009-07-31T11:41:34.648-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RAII'/><category scheme='http://www.blogger.com/atom/ns#' term='inheritance'/><category scheme='http://www.blogger.com/atom/ns#' term='classes'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='core foundation'/><title type='text'>Core Foundation meets C++</title><content type='html'>I am tired of dealing with Core Foundation ornerinesses in a program primarily written in C++, so I decided to write a library of RAII wrappers for Core Foundation classes I use commonly.&lt;br /&gt;&lt;br /&gt;My first problem was that I didn't really understand about overloading assignment operators, but I think I've figured them out now.&lt;br /&gt;&lt;br /&gt;The next concern is that for many types, there are mutable and immutable version, which differ only by a const in their typedef to the opaque underlying type.  My first thought was to implement, for example, CFMutableArrayRef and CFArrayRef wrappers separately.&lt;br /&gt;&lt;br /&gt;My next thought was to set up some kind of inheritance.&lt;br /&gt;Inheritance fails, however.  If we want to say that the wrapper for the immutable inherits from the mutable, and makes some member functions/operators private, then we'll run into the problem that an instance of a derived class must be able to function as an object of the base class, and a derived class wrapping an immutable object cannot act the same as a base object that &lt;em&gt;is&lt;/em&gt; mutable.&lt;br /&gt;&lt;br /&gt;Third try: Make the private data member mutable, but provide a const "conversion operator" that will make it act like it's immutable.  This seems like the best option so far.&lt;br /&gt;&lt;br /&gt;I am planning to make the library available once it's usable.  I am still deciding on the licensing system I wish to use, but I think I am leaning toward BSD-style, or maybe Creative Commons.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-6523446144958179376?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/6523446144958179376/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2009/07/core-foundation-meets-c.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/6523446144958179376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/6523446144958179376'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2009/07/core-foundation-meets-c.html' title='Core Foundation meets C++'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-2304732904168874614</id><published>2009-07-26T18:33:00.004-04:00</published><updated>2009-07-26T19:04:13.597-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='strings'/><category scheme='http://www.blogger.com/atom/ns#' term='core foundation'/><title type='text'>C string to CFString</title><content type='html'>I have a null-terminated string of (random) ASCII chars that I need to convert to a CFString for an API call.  However, the following call yields NULL:&lt;br /&gt;&lt;br /&gt;CFStringRef convertedValue = CFStringCreateWithCString(kCFAllocatorDefault, c_string, kCFStringEncodingUTF8);&lt;br /&gt;&lt;br /&gt;According to the doc, this means "there was a problem creating the object."&lt;br /&gt;I am currently stumped as to why.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-2304732904168874614?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/2304732904168874614/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2009/07/c-string-to-cfstring.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/2304732904168874614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/2304732904168874614'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2009/07/c-string-to-cfstring.html' title='C string to CFString'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-1689223756263673432</id><published>2009-07-15T09:42:00.002-04:00</published><updated>2009-07-15T09:48:32.580-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='system calls'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>launchd confusion</title><content type='html'>Does the following documentation indicate that one may not fork()/exec() in a launchd process?  I'm certainly getting strange console messages when I do, but it's not clear yet if that's due to malformed code or if it's because of the way launchd treats children of children processes.&lt;br /&gt;&lt;br /&gt;Citation: &lt;a href="http://developer.apple.com/macosx/launchd.html"&gt;launchd documentation&lt;/a&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Creating and running a launchd job&lt;br /&gt;&lt;br /&gt;Whether you're migrating a job to launchd from some other system job launcher, or you're setting up a job for a new service, there are a few basic requirements for the job.&lt;br /&gt;&lt;br /&gt;Jobs run from launchd should not duplicate launchd functionality; for instance, they should not use chroot(2). Furthermore, they should not do the things normally required of daemon processes, such as detaching from the terminal they are initially attached to. The only things that are strictly prohibited, however, are fork()/exit() combinations (including indirect methods, such as the daemon(3) library call). A server which attempts to run itself as a daemon in this way will seem to have finished running, potentially leading to launchd respawning it, or disabling the service. As launchd does not get stalled waiting for a child that hasn't yet exited, it's not necessary to try to prevent it. &lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-1689223756263673432?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/1689223756263673432/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2009/07/launchd-confusion.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/1689223756263673432'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/1689223756263673432'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2009/07/launchd-confusion.html' title='launchd confusion'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-4497758377346509215</id><published>2009-07-14T15:31:00.003-04:00</published><updated>2009-07-14T15:35:08.410-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='ipc'/><category scheme='http://www.blogger.com/atom/ns#' term='system calls'/><category scheme='http://www.blogger.com/atom/ns#' term='core foundation'/><title type='text'>CFFork</title><content type='html'>It is absolutely forbidden to use Core Foundation or higher-level APIs in a child process after fork()ing, before exec*()ing.  This royally messes up our process model.&lt;br /&gt;&lt;br /&gt;citation: &lt;a href="http://developer.apple.com/releasenotes/CoreFoundation/CoreFoundation.html"&gt;OS X Leopard Core Foundation Release Notes&lt;/a&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;b&gt;CoreFoundation and fork()&lt;/b&gt;&lt;br /&gt;Due to the behavior of fork(), CoreFoundation cannot be used on the child-side of fork(). If you fork(), you must follow that with an exec*() call of some sort, and you should not use CoreFoundation APIs within the child, before the exec*(). The applies to all higher-level APIs which use CoreFoundation, and since you cannot know what those higher-level APIs are doing, and whether they are using CoreFoundation APIs, you should not use any higher-level APIs either. This includes use of the daemon() function.&lt;br /&gt;&lt;br /&gt;Additionally, per POSIX, only async-cancel-safe functions are safe to use on the child side of fork(), so even use of lower-level libSystem/BSD/UNIX APIs should be kept to a minimum, and ideally to only async-cancel-safe functions.&lt;br /&gt;&lt;br /&gt;This has always been true, and there have been notes made of this on various Cocoa developer mailling lists in the past. But CoreFoundation is taking some stronger measures now to "enforce" this limitation, so we thought it would be worthwhile to add a release note to call this out as well. A message is written to stderr when something uses API which is definitely known not to be safe in CoreFoundation after fork(). If file descriptor 2 has been closed, however, you will get no message or notice, which is too bad. We tried to make processes terminate in a very recognizable way, and did for a while and that was very handy, but backwards binary compatibility prevented us from doing so.&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-4497758377346509215?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/4497758377346509215/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2009/07/fork.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/4497758377346509215'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/4497758377346509215'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2009/07/fork.html' title='CFFork'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-6117059666233494847</id><published>2009-07-07T09:12:00.003-04:00</published><updated>2009-07-09T08:53:09.108-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='strings'/><category scheme='http://www.blogger.com/atom/ns#' term='core foundation'/><title type='text'>cfstring parsing</title><content type='html'>Why are strings so annoying?&lt;br /&gt;&lt;br /&gt;I'm trying to take integer values from a c-string, but only if it's well-formed.  Using CFNumberFormatterGetValueFromString works if I can correctly determine the boundaries of the number portions.  The difficulty is determining where those are.  The formatter still gives a value if the range contains, for example, 5e.  The desired behavior is for it to return false is such a situation.&lt;br /&gt;&lt;br /&gt;Can anyone recommend a better way to parse a CFString, so that I can determine if the string is well-formed, and get the values if so?&lt;br /&gt;&lt;br /&gt;Edit: traversed the c-string, finding ranges and delimeters by hand.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-6117059666233494847?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/6117059666233494847/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2009/07/cfstring-parsing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/6117059666233494847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/6117059666233494847'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2009/07/cfstring-parsing.html' title='cfstring parsing'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-6878625228508526960</id><published>2009-06-28T15:04:00.004-04:00</published><updated>2009-06-29T08:45:27.176-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='authorization'/><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='ipc'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>Elevated Processes</title><content type='html'>Objective-c is an insecure language.  Although the feature is being deprecated (I believe starting with Snow Leopard), a user may override a program's code.&lt;br /&gt;&lt;br /&gt;An application that needs to perform a restricted action can prompt the user for Administrator password using the Security framework.  However, for security reasons, the best methodology is to have a helper application, and launch it using the authorization obtained.  This raises issues of setting +s on the helper tool and interprocess communication.  Allegedly, all of these are very straightforward, but the Apple-provided BetterAuthorizationSample project is written in somewhat arcane C (there are goto statements!), and I find it very difficult to understand what's going on.&lt;br /&gt;&lt;br /&gt;I would appreciate assistance, especially in the form of a non-Apple tutorial or documentation, indicating how to set up communication with an executable that is a secondary target in the same xcodeproj.&lt;br /&gt;&lt;br /&gt;EDIT: Have now gotten helper application to launch.  There was a typo in the filepath I passed to AEWP.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-6878625228508526960?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/6878625228508526960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2009/06/elevated-processes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/6878625228508526960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/6878625228508526960'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2009/06/elevated-processes.html' title='Elevated Processes'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-2367684778759721039</id><published>2009-06-17T13:32:00.002-04:00</published><updated>2009-06-17T13:35:30.730-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='system calls'/><title type='text'>FSGetCatalogInfoBulk</title><content type='html'>I use this call to iterate over directory contents with fewer system calls.  Sometimes, I delete files, and I need to open the iterator with kFSIterateDelete.  The implementation is such that kFSIterateFlat was supposed to be able to permit such a delete-file operation, but does not in fact.&lt;br /&gt;While testing the code, we commented out the actual delete, and found that the last n files in the directory were improperly processed.  When we commented the delete back in, everything was cleared up.&lt;br /&gt;The moral here is clear:  When you open an FSIterator with the kFSIterateDelete flag, make sure to delete the files!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-2367684778759721039?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/2367684778759721039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2009/06/fsgetcataloginfobulk.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/2367684778759721039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/2367684778759721039'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2009/06/fsgetcataloginfobulk.html' title='FSGetCatalogInfoBulk'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-3276895951461698461</id><published>2009-06-02T10:19:00.001-04:00</published><updated>2009-06-02T10:32:59.533-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='core foundation'/><title type='text'>core foundation file manager</title><content type='html'>It's fun to reduce one problem to an already-solved problem.&lt;br /&gt;I was working to remove all uses of the NSFileManager and replace them with faster CF file manager calls.  I have one last function to fix, and even that is done (sans debugging) except that it relies on being able to determine if a file exists at a path held in a CFStringRef.  I have a function&lt;br /&gt;&lt;br /&gt;bool MyClass::fileExistsAtPath(NSString *filePath)&lt;br /&gt;{&lt;br /&gt; &amp;nbsp;&amp;nbsp;return [[NSFileManager defaultManager] fileExistsAtPath:filePath];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;but I want it to be&lt;br /&gt;&lt;br /&gt;bool MyClass::fileExistsAtPath(CFStringRef path)&lt;br /&gt;{&lt;br /&gt; &amp;nbsp;&amp;nbsp;return ???;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;I have been searching the documentation, and I thought I could use a CFURL for this, but so far, I don't see any API that will tell me whether the url is valid.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-3276895951461698461?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/3276895951461698461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2009/06/core-foundation-file-manager.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/3276895951461698461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/3276895951461698461'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2009/06/core-foundation-file-manager.html' title='core foundation file manager'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-9052383151391606342</id><published>2009-05-27T09:24:00.001-04:00</published><updated>2009-06-17T13:35:52.551-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='UI'/><title type='text'>awakeFromNib</title><content type='html'>What does awakeFromNib actually mean?  Using the Cocoa principle of "it's probably what it sounds like," a naive programmer would assume that this method is invoked when the program awakes, i.e. receives focus.  Alas, this is far from accurate.  Someone seems to think that an object created via nib file instead of programmatically requires extra code, and that's possibly true; but "awake from nib?"  Where's the waking up?&lt;br /&gt;&lt;br /&gt;A nib file is an xml archive that in a sense dehydrates Cocoa objects for runtime reconstitution.  However, it can require further tweakage, so every thus-created object receives the awakeFromNib message.  It can be useful, for instance, in establishing connections; the app delegate manager receives awakeFromNib before applicationDidFinishLaunching, so I use it to create some connections such as (instance variable) dockTile = [NSApp dockTile]; which I can then refer to everywhere else in my class, knowing that it will have a valid value immediately after the object is instantiated, before any other code can run.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;- (void)awakeFromNib&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;dockTile = [NSApp dockTile];&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-9052383151391606342?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/9052383151391606342/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2009/05/awakefromnib.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/9052383151391606342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/9052383151391606342'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2009/05/awakefromnib.html' title='awakeFromNib'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3346053520704872623.post-4085080089618367892</id><published>2009-05-18T12:32:00.002-04:00</published><updated>2009-06-17T13:36:16.119-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='UI'/><title type='text'>Cocoa app delegate</title><content type='html'>Programming with the Cocoa APIs has been a very strange experience for me.  My first experience was on the iPhone with Cocoa Touch, and right when I had sort-of figured that out, I had to switch to OS X development.&lt;br /&gt;Yesterday, I figured out how to badge dock icons.  I found the appropriate documentation, but I still didn't understand, so I downloaded the sample project.  Now I had proof of existance, but couldn't see how it was working.  Finally, I opened the nib, and saw that the AppDelegate class was connected via Interface Builder as the NSApplication's delegate, and thus its delegate functions were called as appropriate.&lt;br /&gt;I cannot figure out how to achieve this same goal programmatically, so I copied their method, and it does indeed work.&lt;br /&gt;&lt;br /&gt;EDIT: the following is untested, but seems like it should work:&lt;br /&gt;Create an instance of the delegate class, and in its -awakeFromNib method, insert the follwing code:&lt;br /&gt;[NSApp setDelegate:self];&lt;br /&gt;&lt;br /&gt;the end.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3346053520704872623-4085080089618367892?l=qc-dev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://qc-dev.blogspot.com/feeds/4085080089618367892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://qc-dev.blogspot.com/2009/05/cocoa-app-delegate.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/4085080089618367892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3346053520704872623/posts/default/4085080089618367892'/><link rel='alternate' type='text/html' href='http://qc-dev.blogspot.com/2009/05/cocoa-app-delegate.html' title='Cocoa app delegate'/><author><name>Richard</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
