<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Black Pixel</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/" />
    <link rel="self" type="application/atom+xml" href="http://blackpixel.com/blog/atom.xml" />
    <id>tag:blackpixel.com,2012-10-04:/blog/2</id>
    <updated>2013-05-16T18:18:48Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 5.2</generator>

<entry>
    <title>Now Hiring: Production Designers</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2013/05/now-hiring-production-designers.html" />
    <id>tag:blackpixel.com,2013:/blog//2.691</id>

    <published>2013-05-16T18:14:47Z</published>
    <updated>2013-05-16T18:18:48Z</updated>

    <summary>We are looking for a production designer to lead asset production and style documentation for iOS and Mac applications. This...</summary>
    <author>
        <name>Daniel Pasco</name>
        
    </author>
    
        <category term="Jobs" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p dir="ltr"><span>We are looking for a production designer to lead asset production and style documentation for iOS and Mac applications. This is an entry to mid-level position.</span></p>
<p dir="ltr"><span>We value designers with a passion for great user experiences, a love of stunning iOS and Mac apps, and an eye for pixel-level details.</span></p>
<p dir="ltr"><span>As a part of our team, you'll be participating in some of the highest profile client projects in the industry, as well as on our own products. You will work with dedicated, passionate professionals committed to making some of the best apps in the world.</span></p>
<p>RESPONSIBILITIES</p>
<p>This position is approximately 70% Production Design, with opportunities to contribute and grow across the spectrum of UX design.</p>
<p><span>An ideal candidate is ready to jump in and contribute on a variety of projects. You might be preparing assets in the morning, sketching ideas to solve a design problem after lunch, and working with a developer on implementation in the late afternoon. You're proficient in Photoshop and ready to take your skills to the next level. As many of our employees work remotely, the ability to clearly and effectively communicate across digital channels is a must.</span></p>
<ul>
<li dir="ltr"><span>Work with our senior designers and developers to create usable application assets from PSDs comps</span></li>
<li dir="ltr"><span>Own the Production Design process and create detailed style documentation for development</span></li>
<li dir="ltr"><span>Work with the engineering team to place, tweak, and update application assets as needed</span></li>
<li dir="ltr"><span>Work with our design team to conceptualize, research, sketch, wireframe, design, and document apps</span></li>
<li dir="ltr"><span>Use issue tracking tools, basic Git commands, and add/update assets in Xcode</span></li>
</ul>
<p dir="ltr"><span>QUALIFICATIONS</span></p>
<ul>
<li dir="ltr"><span>Proficient in Photoshop</span></li>
<li dir="ltr"><span>Ability to create usable application assets in Photoshop (if the ustwo Pixel Perfect Precision Handbook makes sense to you you're on the right track)</span></li>
<li dir="ltr"><span>Excellent organizational skills, communication skills, and a strong desire to learn</span></li>
</ul>
<p><span>BENEFITS</span></p>
<p dir="ltr"><span>In addition to being a cool job in a great industry, this position also offers:</span></p>
<ul>
<li dir="ltr"><span>Competitive salary</span></li>
<li dir="ltr"><span>Great health insurance plan, including spouses, domestic partners, and children</span></li>
<li dir="ltr"><span>Our central office is a cozy retreat on Upper Queen Anne in Seattle, Washington; remote work permissible for the right person</span></li>
</ul>
<p>If you think you're a good match for this position, please send your resumé along with a cover letter to info@blackpixel.com.</p>
<p><b id="docs-internal-guid-4a6457ba-ae8b-10c0-c4ea-3f933c7bb0f3"><br /><span></span></b></p>]]>
        
    </content>
</entry>

<entry>
    <title>Simulating Locations with Xcode</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2013/05/simulating-locations-with-xcode.html" />
    <id>tag:blackpixel.com,2013:/blog//2.690</id>

    <published>2013-05-09T17:54:28Z</published>
    <updated>2013-05-10T15:45:40Z</updated>

    <summary>We recently shipped an application that required Location Services for an event that was happening in Atlanta. Since our team...</summary>
    <author>
        <name>Brandon Alexander</name>
        <uri>http://blackpixel.com</uri>
    </author>
    
        <category term="Articles" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p>We recently shipped an application that required Location Services for an event that was happening in Atlanta. Since our team is distributed across the country, it simply wasn't feasible to send everyone to Atlanta for a couple weeks to test things out. I happen to live in the Atlanta area and getting down to the Georgia Dome is a day trip for me. I really wanted to find a way to limit my time in downtown Atlanta.</p>

<p>This is where things get exciting. Apple's engineers have given us the ability to simulate locations within our applications. This simulation works for both the device and the simulator.</p>

<p>Before we get started, we need to go over one important thing. When you simulate a location on a device, Location Services has been hijacked until you deploy your app with location simulation turned off. Be sure to keep that in mind before you start testing on a personal device (you know you do it...) and wreaking havoc on all of your location based apps.</p>

<h2>GPX Files</h2>

<p>Xcode uses a standardized file type to simulate locations. The GPX spec defines many different ways to define a path or a set of geolocation coordinates. Xcode only uses the <code>&lt;wpt&gt;</code> tag so if you find a tool that generates <code>&lt;rte&gt;</code> or <code>&lt;trk&gt;</code> based gpx files, Xcode won't be able simulate your location properly. </p>

<p>You can find more information about GPX files here: <a href="http://en.wikipedia.org/wiki/GPS_eXchange_Format">http://en.wikipedia.org/wiki/GPS<em>eXchange</em>Format</a></p>

<h2>Generating GPX Files</h2>

<p>To create valid GPX files Xcode can use, I have found two great resources.</p>

<p>If I need to have one location simulated, I'll head over to <a href="http://gpx-poi.com">http://gpx-poi.com</a> and create a single waypoint file. Click download and save it in a convenient location on your filesystem.</p>

<p><img alt="gpx-poi.png" src="http://blackpixel.com/blog/2013/05/09/gpx-poi.png" width="640" height="465" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></p>

<p>Things get a little more complicated if I want to simulate a series of waypoints. To accomplish this, I found this site: <a href="http://www.elsewhere.org/journal/gmaptogpx/">http://www.elsewhere.org/journal/gmaptogpx/</a></p>

<p>If you follow the instructions for creating the bookmarklet and go to Google Maps, pull up some driving directions, and activate the bookmarklet, you'll see a screen similar to this one:</p>

<p><img alt="gmaptogpx.png" src="http://blackpixel.com/blog/2013/05/09/gmaptogpx.png" width="506" height="350" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></p>

<p>Selecting the "Points" option will generate the proper type of GPX file. Once the file is generated, copy the text and paste it into a new document and name it something meaningful with the <code>gpx</code> extension.</p>

<p>We're now ready to simulate our location.</p>

<h2>Now to Xcode</h2>

<p>For the following we're going to use the project found on GitHub: <a href="https://github.com/whilethis/location-simulation">https://github.com/whilethis/location-simulation</a>. You'll need Xcode 4.2 or newer to use this feature. I was using Xcode 4.6.2 just in case your screens look slightly different.</p>

<p>Using Xcode, we can simulate our locations two ways.</p>

<p>The first way is to have the location simulated from application launch. To do this, we need to open up the Scheme Editor (Product->Scheme->Edit Scheme or Command+Shift+,) and make sure the "Allow Location Simulation" checkmark is checked. To import the freshly created gpx file, open the dropdown control and select "Add GPX File to Project...". Navigate to the file and select it and have Xcode copy the file into the destination group's folder.</p>

<p><img alt="scheme.png" src="http://blackpixel.com/blog/2013/05/09/scheme.png" width="701" height="477" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></p>

<p>You might have noticed a large list of cities you can also select to simulate. These are the same as a single waypoint GPX file.</p>

<p>The second way to simulate a location is through the debugger. To do this, you need to have location simulation enabled through the scheme editor and any location (or no location) chosen in the dropdown control. Set a breakpoint in the project (for the sample project, somewhere in <code>application:didFinishLaunchingWithOptions:</code> will suffice). Run the application and when the breakpoint is triggered you'll see the Location Services icon in the jump bar of the debug area.</p>

<p><img alt="debugger.png" src="http://blackpixel.com/blog/2013/05/09/debugger.png" width="705" height="378" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></p>

<p>Select your location and then run the application and Location Services will now run through the simulated locations in the GPX file.</p>

<p>Nick Arnott, QA lead at Double Encore, recently wrote a <a href="http://www.doubleencore.com/2013/04/using-xcode-to-test-location-services/">similar article</a> on the topic. While the tools I regularly use do the job, I'd love to have some better tools for generating GPX files based on actual routes. </p>

<p>"Hey, I have this idea for an app..."</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Now Hiring: Sales</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2013/04/now-hiring-sales.html" />
    <id>tag:blackpixel.com,2013:/blog//2.689</id>

    <published>2013-05-01T02:42:17Z</published>
    <updated>2013-05-01T02:43:08Z</updated>

    <summary>We&apos;re looking for salespeople to help us reach out to new clients! Although we already do a brisk business via...</summary>
    <author>
        <name>Daniel Pasco</name>
        
    </author>
    
        <category term="Jobs" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p dir="ltr"><span>We're looking for salespeople to help us reach out to new clients! Although we already do a brisk business via word of mouth and high-level referrals, we'll be relying on you to help us identify new clients and markets, and to represent our team to them.</span></p>
<p>We have a phenomenal team of developers and designers that has the capacity to create amazing applications,  and we'll be looking to you to help us connect with new customers looking for solid and delightful apps.</p>
<p>You'll have the support of our management team, and our design and development staff to help put together bids and proposals as a part of this process.</p>
<p>LOCATION</p>
<p dir="ltr"><span>Anywhere in the United States, provided you have great communication skills and are comfortable working remotely. Being based in Seattle is a bonus but not mandatory for consideration.</span></p>
<p>RESPONSIBILITIES</p>
<p dir="ltr"><span>You will work directly with our management team to help ensure that we are keeping our client team engaged on projects with great clients.</span></p>
<p>Tracking down new leads and making cold calls will be an inherent part of this business, but we will also provide a travel budget to allow you to attend conferences and make connections with customers as well.</p>
<p>Face-to-face visits with potential clients will be a common occurrence as a part of this position, so an ability to travel on relatively short notice will be required.</p>
<p>An enthusiasm for great apps and iOS, and a basic working knowledge of our team's technical capabilities will be a critical requirement for this position.</p>
<p>Sensitivity to the needs of prospective clients is also a must.</p>
<p>QUALIFICATIONS</p>
<ul>
<li dir="ltr">
<p dir="ltr"><span>A demonstrated track record for finding and creating new opportunities with high profile clients. </span></p>
</li>
<li dir="ltr">
<p dir="ltr"><span>Familiarity with iOS devices and applications</span></p>
</li>
<li dir="ltr">
<p dir="ltr"><span>Strong communication and organizational skills</span></p>
</li>
</ul>
<p>SOFTWARE SKILLS</p>
<p dir="ltr"><span>Comfort using applications such as Pages, Numbers, etc.</span></p>
<p><b><b><span></span></b></b></p>
<p dir="ltr"><span>BENEFITS</span></p>
<p dir="ltr"><span>In addition to being a cool job in a great industry, this position also offers:</span></p>
<ul>
<li dir="ltr">
<p dir="ltr"><span>Competitive compensation</span></p>
</li>
<li dir="ltr">
<p dir="ltr"><span>Great health insurance plan, including spouses, domestic partners, and children</span><span></span></p>
</li>
<li dir="ltr">
<p dir="ltr"><span>The option to work remotely</span></p>
</li>
</ul>
<p dir="ltr"><span>If you think you're a good match for this position, please send your resumé along with a cover letter to </span><span>info@blackpixel.com</span><span>.</span><span></span></p>
<p><span> </span></p>]]>
        
    </content>
</entry>

<entry>
    <title>Now Hiring: Project Management</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2013/04/now-hiring-project-management.html" />
    <id>tag:blackpixel.com,2013:/blog//2.688</id>

    <published>2013-05-01T02:38:52Z</published>
    <updated>2013-05-01T02:45:41Z</updated>

    <summary>We&apos;re looking for project managers to join our team! Ideal candidates will have 5 to 7 years of total experience...</summary>
    <author>
        <name>Daniel Pasco</name>
        
    </author>
    
        <category term="Jobs" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p dir="ltr"><span>We're looking for project managers to join our team! Ideal candidates will have 5 to 7 years of total experience with a strong recent emphasis on iOS and agile methodologies. </span></p>
<p>We have a phenomenal team of developers and designers that are looking for you to keep an eye on the overall project while they focus on kicking ass.</p>
<p>You'll work with them and some of the top clients in the world to help ensure that the right things get done at the right time. As the interface to our clients, you will need to be ready to travel and represent the company on site for some projects, and will be able to work remotely (as most of us generally do) on others.</p>
<p>This is a great opportunity for someone with great management experience and an ability to collaborate with a remote team. You'll be working with some of the best designers in the industry, and a development team that can move mountains.</p>
<p>LOCATION</p>
<p dir="ltr"><span>Anywhere in a reasonable time zone, provided you have great communication skills and are comfortable working remotely. Being based in Seattle is a bonus but not mandatory for consideration.</span></p>
<p>RESPONSIBILITIES</p>
<p dir="ltr"><span>You will act as a liaison between our clients and the team, and will collaborate with both to define tasks for sprints throughout the project. You will serve as a general point of contact for day to day project-related issues for the client.</span></p>
<p>Although QA support will be provided, it is expected that you will have direct, hands-on familiarity with the products we create, trying out new builds and getting a personal sense of the state of the application throughout the project.</p>
<p dir="ltr"><span>Frequent travel may be required for some clients.</span></p>
<p dir="ltr"><span>QUALIFICATIONS</span></p>
<ul>
<li dir="ltr"><span>Experience managing 2- to 8-person iOS projects</span></li>
<li dir="ltr"><span>Experience with Agile methodology</span></li>
<li dir="ltr"><span>Familiarity with issue trackers, JIRA and FogBugz experience is a plus</span></li>
<li dir="ltr"><span>Ability to work within deadlines</span></li>
<li dir="ltr"><span>Strong communication and organizational skills</span></li>
</ul>
<p dir="ltr"><span>BENEFITS</span></p>
<p dir="ltr"><span>In addition to being a cool job in a great industry, this position also offers:</span></p>
<ul>
<li dir="ltr"><span>Competitive salary</span></li>
<li dir="ltr">Great health insurance plan, including spouses, domestic partners, and children</li>
<li dir="ltr">Work remotely</li>
</ul>
<p dir="ltr"><span>If you think you're a good match for this position, please send your resumé along with a cover letter to </span><span>info@blackpixel.com</span><span>.</span><span></span></p>
<p><span> </span></p>]]>
        
    </content>
</entry>

<entry>
    <title>Now Hiring: QA</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2013/04/now-hiring-qa.html" />
    <id>tag:blackpixel.com,2013:/blog//2.687</id>

    <published>2013-05-01T02:36:40Z</published>
    <updated>2013-05-01T02:46:28Z</updated>

    <summary>We&apos;re looking for another QA god to join the Black Pixel pantheon and terrorize our team! Ideal candidates will have...</summary>
    <author>
        <name>Daniel Pasco</name>
        
    </author>
    
        <category term="Jobs" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p dir="ltr"><span>We're looking for another QA god to join the Black Pixel pantheon and terrorize our team! Ideal candidates will have 2 or more years of QA experience, and a demonstrated knack for ferreting out issues  that will haunt the dreams of our development team for years to come. </span></p>
<p>We have a phenomenal team of developers and they will rest easy knowing that they are in your care, relying on your swift action and inexorable, relentless quest to find out what they have screwed up.</p>
<p>Our QA staff are a valued part of our team - they work closely with our developers and designers and make a point of communicating issues and concerns as they arise.</p>
<p>LOCATION</p>
<p dir="ltr"><span>Anywhere in a reasonable time zone, provided you have great communication skills and are comfortable working remotely. Being based in Seattle is a bonus but not mandatory for consideration.</span></p>
<p>RESPONSIBILITIES</p>
<p dir="ltr"><span>The kind of QA person we're looking for will know as much about the current state of the application's requirements as any developer, designer, or project manager. They will know the ins and outs of iOS and OS X and will be experienced enough to know the kinds of edge cases and transitions that can come up for apps on these platforms.</span></p>
<p>Many QA positions are considered an entry-level position, and are paid accordingly. This is not that position! You're expected to be great at what you do, and compensation is commensurate with this.</p>
<p>You will amaze and terrify us with the variety of conditions under which you will find bugs. You will have the moxie to be on the lookout for regressions when things change and will be knowledgeable enough to volunteer possible risks when you hear about proposed changes.</p>
<p>Your bug reports will read like a best-selling detective story - including steps to reproduce, expected results, and what actually happened. You will have a good enough understanding of the product you are testing to cultivate a sense of when multiple issues stem from a single underlying bug.</p>
<p>QUALIFICATIONS</p>
<ul>
<li dir="ltr"><span>2 or more years QA experience</span></li>
<li dir="ltr"><span>Strong familiarity with iOS and OS X</span></li>
<li dir="ltr"><span>Relentless eye for detail</span></li>
<li dir="ltr"><span>Familiarity with issue trackers, FogBugz and JIRA experience a plus</span></li>
<li dir="ltr">Ability to create <a href="http://mhay68.tumblr.com/post/1648223018/what-makes-a-good-bug-report">detailed bug reports</a></li>
<li dir="ltr"><span>Strong communication and organizational skills</span></li>
<li dir="ltr"><span>Excellent referrals from people familiar with your work</span></li>
<li dir="ltr"><span>Experience with Xcode is a plus</span></li>
</ul>
<p dir="ltr"><span>BENEFITS</span></p>
<p dir="ltr"><span>In addition to being a cool job in a great industry, this position also offers:</span></p>
<ul>
<li dir="ltr"><span>Competitive salary</span></li>
<li dir="ltr"><span>Great health insurance plan, including spouses, domestic partners, and children</span></li>
<li dir="ltr"><span>Work remotely</span></li>
</ul>
<p><span>If you think you're a good match for this position, please send your resumé along with a cover letter to </span><span>info@blackpixel.com</span><span>.</span><span></span></p>
<p><span> </span></p>]]>
        
    </content>
</entry>

<entry>
    <title>Interview Questions for iOS and Mac Developers </title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2013/04/interview-questions-for-ios-and-mac-developers-1.html" />
    <id>tag:blackpixel.com,2013:/blog//2.686</id>

    <published>2013-04-11T18:48:58Z</published>
    <updated>2013-04-12T14:01:53Z</updated>

    <summary>Most iOS contract houses tend to have one or two experienced developers, along with a large number of junior people....</summary>
    <author>
        <name>Daniel Pasco</name>
        
    </author>
    
        <category term="Articles" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Posts" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p>Most iOS contract houses tend to have one or two experienced developers, along with a large number of junior people. It is also common to classify anyone with more than 3 years of experience work with Cocoa to as 'senior'. At Black Pixel, most of the developers on our staff have 7 to 10 years of Cocoa experience, and many of them are ex-Apple product engineers. The few 'junior' developers we have would be considered very senior anywhere else.</p>
<p>It's critical that the people we hire are good enough to keep up with the rest of the team: we run at a fast pace, and a new hire that can't keep up will make things harder for their people we're working with. Plus, it's not really fair to throw someone into the deep end of the pool without giving them some idea of how hard they are going to have to work in order to catch up with everyone else.</p>
<p>An applicant's final interview is with me. Over time I noticed that I was recommending that we pass on a lot of the candidates that I was meeting with, not because of any particular harshness on my part, but because it became clear that they were going to be struggling to hold their own with the rest of the team.</p>
<p>I eventually distilled my questions down to a basic list and started asking people to run these by applicants before recommending that they interview with me. This is by no means a comprehensive list, but it's enough to get a feel for where people are in their technical progress.</p>
<p>I'm generally looking for "yes" (where applicable) to all of these, along with the ability to speak knowledgeably about their experiences:</p>
<p>1. How do you handle asynchronous networking?</p>
<p>2. Have you ever worked with multi-threaded Core Data?<br />* How was it?<br />* What approach did you use?</p>
<p>3. Have you ever worked with Core Animation?<br />* Can you tell me about that?<br />* What kind of animations? (grace notes for an app versus canned table view insertion or bulk affine transforms)</p>
<p>4. Have you ever worked with Core Graphics? (answer for Mac devs should be a resounding "HELL YES I DID")<br />* What kinds of things did you do?</p>
<p>5. Have you ever filed any verified issues against Apple frameworks on radar?<br />* Can you describe them to me?<br />* Better still, can you point them out on open radar?</p>
<p>6. Compare and contrast NSNotification vs KVO.<br />* When would you use one or the other? What are the implications of using them?</p>
<p>7. Have you ever worked with NSOperationQueue?<br />* What did you use it for?</p>
<p>8. Please tell me about your Core Text experience.</p>
<p>9. How would you use NSURLConnection on a background thread?</p>
<p>10. What kinds of issues should someone be aware of when working with blocks?</p>
<p>11. Have you ever built any custom frameworks or libraries?<br />* What's your preferred method of working on an application in parallel with a library?</p>
<p>These are standard, practical technologies we work with every day, not an abstract set of obscurities we're asking about out of some kind of elitism. I don't necessarily expect a solid command of all of these, but if someone can't clearly and articulately get through a conversation about the majority of them, they probably aren't ready to be a good fit for our team.</p>
<p>Asking questions like these helps ensure that the developers we bring on board at least have enough of a technical background to get started working with us, and they also give the people applying an idea of areas we'd like to see them improve on if they want to try and come on board further down the road.</p>
<p>Obviously the person asking the questions has to have a good enough command of the material to assess the responses, but I've found this to be a fairly concise way to get a temperature read on an applicant's skill set. If you're looking for a senior developer for your company, these questions might help you determine if the person you're talking to is a good technical fit, too.</p>
<p>Likewise, if your lead developer can't talk about these technologies intelligently, that person isn't going to be able to advise which to use in a given situation. If that person isn't actively seeking out people who can help with gaps in their expertise, you're likely in for trouble.</p>
<p>-Daniel</p>]]>
        
    </content>
</entry>

<entry>
    <title>The Return of NetNewsWire</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2013/03/the-return-of-netnewswire.html" />
    <id>tag:blackpixel.com,2013:/blog//2.682</id>

    <published>2013-03-19T21:55:20Z</published>
    <updated>2013-03-20T21:30:52Z</updated>

    <summary>Given the discontinuation of Google Reader, I wanted to take a moment to talk about our plans for NetNewsWire. First,...</summary>
    <author>
        <name>Daniel Pasco</name>
        
    </author>
    
        <category term="Posts" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p dir="ltr">Given the <a href="http://googlereader.blogspot.com/2013/03/powering-down-google-reader.html">discontinuation of Google Reader</a>, I wanted to take a moment to talk about our plans for <a href="http://netnewswireapp.com">NetNewsWire</a>.</p>
<p>First, we intend to bring sync to future versions of NetNewsWire. It's too soon to go into details about this, but you should know that we recognize how extremely important it is and that it is a top priority for us.</p>
<p>Second, even though we've been quiet about it, we have been working on new versions of NetNewsWire for Mac, iPhone, and iPad. We have some great new features and a modern design that we can't wait to show you.</p>
<p>Our intent when we acquired NetNewsWire was to give it just as much love and attention as we recently gave to <a href="http://kaleidoscopeapp.com">Kaleidoscope 2</a>. Much of last year was spent on moving NetNewsWire for Mac forward to keep up with the times, and we completely rewrote the iPhone and iPad versions of it from scratch.</p>
<p>As far as sync is concerned, we knew we would likely need an alternative to Google Reader as early as last year. At the time, the option that seemed to make the most sense was to embrace iCloud and Core Data as the new sync solution of choice. We spent a considerable amount of time on this effort, but iCloud and Core Data syncing had issues that we simply could not resolve.</p>
<p>iCloud hasn't worked out for us and Google's announcement solidified and accelerated our plans. We love NetNewsWire and its users and we are working hard to provide an update on par with the quality of work you've seen from us in Kaleidoscope 2.</p>
<p>We will keep you up to date as NetNewsWire development progresses and look forward to shipping new versions that are worthy of the name and history you have come to expect. We're excited to share these with you, and we hope you'll love them just as much as we do.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Comparing Text from Anywhere with Kaleidoscope 2</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2013/02/comparing-text-from-anywhere-with-kaleidoscope-2.html" />
    <id>tag:blackpixel.com,2013:/blog//2.680</id>

    <published>2013-02-08T22:00:00Z</published>
    <updated>2013-02-08T22:06:04Z</updated>

    <summary>In Kaleidoscope 2, we&#8217;ve added several new features to make it faster and easier than ever to compare text, images,...</summary>
    <author>
        <name>Michael Gorbach</name>
        
    </author>
    
        <category term="Posts" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p>In <a href="http://www.kaleidoscopeapp.com">Kaleidoscope 2</a>, we&#8217;ve added several new features to make it faster and easier than ever to compare text, images, and folders. Today we&#8217;d like to show you a simple way to compare text or images from anywhere on your Mac with Kaleidoscope using OS X Services. </p>

<p>One of the best things about Services is that you can use them to compare several pieces of text directly, without worrying about saving each snippet to a separate file. <a href="https://vimeo.com/59258560">Let&#8217;s take a look</a>.</p>

<iframe src="http://player.vimeo.com/video/59258560" width="500" height="313" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>

<p>The quickest way to find Kaleidoscope&#8217;s text comparison Service is to look for it in the &#8220;Services&#8221; section of the context menu that comes up whenever you right click on selected text. Select the text you want to compare, choose the &#8220;Compare Text in Kaleidoscope&#8221; service from the context menu, and Kaleidoscope will launch and pre-populate a new document with your text. </p>

<p>To add more text simply select &#8220;Compare Text in Kaleidoscope&#8221; for any other text selections and Kaleidoscope will automatically add them to the same comparison document.</p>

<p>There are two other ways to get to Kaleidoscope&#8217;s services. You can find them in the &#8220;Services&#8221; menu of the Main Menu Bar, under the name of your current application (for example, under Safari → Services in Safari). For even more speed, you can assign keyboard shortcuts directly to &#8220;Compare Text in Kaleidoscope&#8221; so you can use it without taking your hands off the keyboard. Open System Preferences, go to the Keyboard preference pane, and select &#8220;Keyboard Shortcuts&#8221; at the top of the pane. Select &#8220;Services&#8221; from the list on the left, and you&#8217;ll find Kaleidoscope&#8217;s services under the &#8220;Pictures&#8221;, &#8220;Files and Folders&#8221;, and &#8220;Text&#8221; groups on the right.</p>

<p>At Black Pixel, we use this feature constantly to quickly compare bits of text. We hope you find it as helpful as we do.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Black Pixel Welcomes Chris Clark</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2013/01/black-pixel-welcomes-chris-clark.html" />
    <id>tag:blackpixel.com,2013:/blog//2.679</id>

    <published>2013-01-02T21:49:00Z</published>
    <updated>2013-01-02T21:56:36Z</updated>

    <summary>I am pleased to announce that Chris Clark has returned to resume his role as an active partner and Chief...</summary>
    <author>
        <name>Daniel Pasco</name>
        
    </author>
    
        <category term="Posts" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p>I am pleased to announce that <a href="http://twitter.com/clarko" title="Chris Clark" target="_blank">Chris Clark</a> has returned to resume his role as an active partner and Chief Designer at Black Pixel. Chris rejoins us after two years helping revolutionize mobile payments at Square.</p>
<p></p>
<p>Chris was instrumental in defining Black Pixel's design culture and helped lay the path for our design team's growth over the last few years. In that time <a href="http://twitter.com/jaimeejaimee" title="Jaimee Newberry">Jaimee Newberry</a>, <a href="http://twitter.com/philletourneau" title="Phil Letourneau">Phil Letourneau</a>, <a href="http://twitter.com/charavel" title="Olivier Charavel">Olivier Charavel</a>, <a href="http://twitter.com/kenfinney" title="Ken Finney">Ken Finney</a>, and <a href="http://twitter.com/iconmaster" title="John Marstall">John Marstall</a> have come on board and contributed their expertise to create great products.</p>
<p></p>
<p>Chris brings a wealth of expertise including phenomenal user experience design skills, unsurpassed attention to detail, uncanny iOS and OS X platform knowledge, and a strong sense for product strategy. Chris raises the bar for quality higher than anyone I have ever met. His addition to our talented design team solidifies Black Pixel as a center for beautiful design and skilled engineering.</p>
<p></p>
<p>My individual experiences of working with Chris Clark and <a href="http://twitter.com/jury" title="Michael Jurewitz">Michael Jurewitz</a> have been amazing. Working with both of these aces on the same team defies articulation, except to say that they play off of each other's strengths with unbelievable virtuosity. I'm incredibly excited at the work we have in store under these two in 2013.</p>
<p></p>
<p>Welcome back, Chris. We missed you.</p>
<p></p>
<p>-Daniel</p>]]>
        
    </content>
</entry>

<entry>
    <title>Code Reviews with Kaleidoscope</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2012/11/code-review-kaleidoscope.html" />
    <id>tag:blackpixel.com,2012:/blog//2.678</id>

    <published>2012-11-28T00:35:00Z</published>
    <updated>2012-11-28T04:47:45Z</updated>

    <summary>In Kaleidoscope 2 we have made version control integration even better and easier to use. We would like to show...</summary>
    <author>
        <name>Doug Russell</name>
        
    </author>
    
        <category term="Posts" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p>In <a href="http://kaleidoscopeapp.com/beta">Kaleidoscope 2</a> we have made version control integration even better and easier to use. We would like to show you one of the many ways you can take advantage of this in Git with a simple but wonderful alias we call <code>ksreview</code>.</p>

<p><code>KSReview</code> is a useful way to do code reviews of feature branches. <code>KSReview</code> compares all of the work done on a feature branch since it diverged from master (or from another branch you specify) while filtering out any other activity from that branch that might otherwise get in your way. We use this ourselves every day and we think it is a fantastic way to do code reviews. Take a look:</p>

<iframe src="http://player.vimeo.com/video/54409133" width="500" height="313" frameborder="0" style="margin-bottom:30px;" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>

<h3>Installing KSReview</h3>

<p>To install <code>ksreview</code> from the command line, just enter the following:</p>

<p><code>git config --global alias.ksreview '!f() { local SHA=${1:-HEAD}; local BRANCH=${2:-master}; if [ $SHA == $BRANCH ]; then SHA=HEAD; fi; git difftool -y -t Kaleidoscope $BRANCH...$SHA; }; f'
</code></p>

<h3>Using KSReview</h3>

<p>To use <code>ksreview</code> while you're on the feature branch, assuming your mainline branch is master, just enter the following at the command line:</p>

<p><code>git ksreview</code></p>

<p>If you're on a different branch or your mainline isn't master, you can be more specific:</p>

<p><code>git ksreview feature-branch-name-or-sha mainline-branch-name</code></p>

<p>We hope you enjoy using <code>ksreview</code>!</p>

<p>UPDATE:</p>

<p><a href="https://twitter.com/eridius">Kevin Ballard</a> was kind enough to lend us some of his bash <a href="https://gist.github.com/4159011">know how</a> so we've updated our instructions for installing  <code>ksreview</code> above. If you installed the earlier version you're fine to keep using it, but if you'd like to update, just follow the install instructions above.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Announcing the Kaleidoscope 2 Public Beta</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2012/11/announcing-the-kaleidoscope-2-public-beta.html" />
    <id>tag:new.blackpixel.com,2012:/blog//2.677</id>

    <published>2012-11-19T16:00:00Z</published>
    <updated>2012-11-19T23:57:29Z</updated>

    <summary> Black Pixel is pleased to announce the public beta of Kaleidoscope 2. This is the best version of Kaleidoscope...</summary>
    <author>
        <name>Daniel Pasco</name>
        
    </author>
    
        <category term="Posts" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p class="p1"><span class="s1"><img alt="Kaleidoscope 2 beta" src="/blog/assets/2012_11_19_kaleidoscope-beta.png" width="743" height="357" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /><br /></span></p>

<p class="p1"><span class="s1">Black Pixel is pleased to announce the public beta of Kaleidoscope 2. This is the best version of Kaleidoscope yet and we are excited to show it to you. </span></p>

<p class="p1">Kaleidoscope is one of the world&#8217;s best tools for spotting differences in images and text and now it supports merging of files and folders, too. Best of all, Kaleidoscope integrates directly with Git, Subversion, Mercurial, and Bazaar to fit perfectly in your workflow.</p>

<p class="p1">Starting today, you can download a public beta of Kaleidoscope 2 and try it free for 15 days. If you like it, you can buy it for $34.99 &#8212; 50% off the final retail price. Buying Kaleidoscope 2 will give you access to all Kaleidoscope 2 public beta builds and all future versions of Kaleidoscope 2. We will be releasing new builds frequently over the coming weeks. We want your feedback and you get a great product at a fantastic discount. </p>

<p class="p1"><b>Designers</b> can use Kaleidoscope to compare photos and graphics in powerful ways to quickly spot the differences between comps or UI elements. <b>Writers</b> can use Kaleidoscope to tell the difference between text content <i>and</i> merge that content into a final document. <b>Developers</b> can use it to diff and merge their source files, powered by direct integration with your source control system of choice. And <b>just about anyone</b> can use it to compare folders to see what has changed and copy files back and forth.</p>

<p class="p1">We are sure you will love Kaleidoscope 2. Download it today and give it a try. You can find out more about Kaleidoscope 2 at <a href="http://www.kaleidoscopeapp.com/beta"><span class="s2">http://kaleidoscopeapp.com/beta</span></a>.</p>

<p class="p1">Sincerely,</p>

<p class="p1">Daniel Pasco</p>
]]>
        

    </content>
</entry>

<entry>
    <title>iPhone 5 - Form follows function</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2012/09/iphone-5-form-follows-function.html" />
    <id>tag:new.blackpixel.com,2012:/blog//2.676</id>

    <published>2012-09-20T23:40:41Z</published>
    <updated>2012-11-18T04:54:14Z</updated>

    <summary>In the past week many pundits have claimed: There is nothing not to like about the phone. It&#8217;s aces. Just...</summary>
    <author>
        <name>Daniel Pasco</name>
        
    </author>
    
        <category term="Posts" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p>In the past week many pundits have claimed:</p>

<p><aside class="pullquote"><div class="inner"><blockquote cite="http://www.wired.com/gadgetlab/2012/09/the-iphone-5-is-boring-and-amazing/"><p>There is nothing not to like about the phone. It&#8217;s aces. Just aces&#8230;.And yet it is also so, so cruelly boring.</p></blockquote><div class="cite"><p class="author">&#8212; Mat Honan</p><p class="occupation">Wired</p></div><!-- /end .cite --></div><!-- /end .inner --></aside></p>

<p>And rinse, wash, repeat around the tech blogosphere. Somehow this amazing device that is clearly &#8220;aces&#8221;, is also the most boring thing since sliced bread. But viewing the iPhone&#8217;s evolution this way is fundamentally misguided. The same author from above gets miraculously close to hitting on just what is unique about what Apple is doing:</p>

<p><aside class="pullquote"><div class="inner"><blockquote cite="http://www.wired.com/gadgetlab/2012/09/the-iphone-5-is-boring-and-amazing/"><p>But the thing is, Apple never just casually moves on to the next thing. It doesn&#8217;t Sony-up and release new products for the sake of releasing them. Instead, it keeps its product line focused, and meticulously refines it year after year, making everything a little bit better. Which means by four or five generations in, especially when it comes to industrial design, Apple&#8217;s products tend to hit a sweet spot, where changing them isn&#8217;t going to improve them. It might even make them worse.</p></blockquote><div class="cite"><p class="author">&#8212; Mat Honan</p><p class="occupation">Wired</p></div><!-- /end .cite --></div><!-- /end .inner --></aside></p>

<p>This is the key &#8212; change for the sake of being different, without being better, is bad. Well-designed tools tend to become static things: the basic problems have been solved. There is a ton of room for refinement, but not for large scale changes.</p>

<h2>Good Design Is Long Lasting</h2>

<p><a href="http://en.wikipedia.org/wiki/Dieter_Rams">Dieter Rams</a>, who was highly influential to Apple&#8217;s industrial design sensibilities, summed it up best in one of his <a href="http://www.archdaily.com/198583/dieter-rams-10-principles-of-"good-design"/">10 Principles of Good Design</a>:</p>

<p><aside class="pullquote"><div class="inner"><blockquote cite="http://www.archdaily.com/198583/dieter-rams-10-principles-of-"good-design"/"><p><b>Good Design Is Long-lasting</b> It avoids being fashionable and therefore never appears antiquated. Unlike fashionable design, it lasts many years - even in today&#8217;s throwaway society.</p></blockquote><div class="cite"><p class="author">&#8212; Dieter Rams</p></div><!-- /end .cite --></div><!-- /end .inner --></aside></p>

<p>Most of our everyday tools - table knives and forks, claw hammers, steering wheels - have not seen any radical changes because at some point, someone figured out the best form to suit the function. It is hard to find a way to change these things that will actually result in something better. iPhone is no exception.</p>

<p>Apple captured the essentials of the iPhone&#8217;s design before they released the original model in 2007: a dominating screen, one simple button on the main face, touch-based keyboards and as few switches and ports as reasonably possible. The primary purpose of the device is to get out of the user&#8217;s way and what they are trying to do. When you&#8217;re running an app, or making a call, the iPhone becomes that app. When powered down, the device is beautiful in a minimalist, modern way, but every single aspect of the hardware serves an important function.</p>

<p>They nailed the design from the start. Certainly there is room for refinement and polish, but the soul of this design is long-lasting.</p>

<h2>Refinements</h2>

<p>What Apple <em>is</em> doing is pouring vast amounts of money and time into continuously refining their great, long-lasting design concept. They are folding in new technology and production processes where they meet specific needs. The result is something <a href="http://daringfireball.net/2012/09/iphone_5">really nice</a>.</p>

<p>What&#8217;s exciting about the new iPhone is what&#8217;s on the <em>inside</em>, both physically inside the phone, and what those things can do for the apps running on iOS 6. Airplay mirroring, which was introduced in iOS 5, is a great example of this. Airplay didn&#8217;t require hardware modifications, just innovation in the underpinnings of the operating system itself.</p>

<p>Apple is doing their own chip fab, to get things faster, smaller, and lighter. They&#8217;re using their control of hardware and software to make this design even more perfect. Other competitors don&#8217;t have the advantage of that vertical integration. It&#8217;s going to be hard to match.</p>

<p>As a result of this customization, the iPhone 5 is reportedly twice as fast as the 4S, without sacrificing battery life.</p>

<p>This is especially exciting because some of our clients are only interested in supporting the latest, most powerful iOS device in the lineup. The apps they want to build need to push the platform to the limits of its capabilities. I can&#8217;t wait to see what our apps can do on the new iPhone when we pull out all the stops.</p>

<p>I&#8217;ll be standing in line to get mine tomorrow morning.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Black Pixel Welcomes Michael Jurewitz</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2012/07/black-pixel-welcomes-michael-jurewitz.html" />
    <id>tag:new.blackpixel.com,2012:/blog//2.675</id>

    <published>2012-07-02T15:48:41Z</published>
    <updated>2012-10-17T23:35:09Z</updated>

    <summary>I am thrilled to announce that Michael Jurewitz will be joining Black Pixel in a director-level position and as a...</summary>
    <author>
        <name>Daniel Pasco</name>
        
    </author>
    
        <category term="Posts" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p>I am thrilled to announce that<a title="Michael Jurewitz" href="http://www.jury.me/"> Michael Jurewitz</a> will be <a title="New Beginnings" href="http://www.jury.me/new-beginnings/">joining Black Pixel</a> in a director-level position and as a partner. Michael recently left Apple after working for seven years in Apple&#8217;s Worldwide Developer Relations team.</p>

<p>Since we first met Michael it was clear that his values and ours were very much in sync. We are passionate about making great products for Apple platforms and Michael joins us in that passion.</p>

<p>Michael&#8217;s role at Black Pixel will be a broad one: He will join us in working directly on client and internal software projects, will work with our engineering team to maintain technical best practices, will work with our design team to ensure our user experiences remain simple yet powerful and beautiful, will assist with identifying strategic directions and planning company priorities, and will help us maintain the high standards of excellence that our clients expect of us and that we expect of ourselves.</p>

<p>Michael and I have spent an unbelievable amount of time talking over the years, both in the abstract, and later, in more concrete exchanges of ideas, goals, and viewpoints. Michael, to me represents some of the very best things I have come to know about Apple&#8217;s culture: He is hard working, practical, concerned about the big picture as well as sweating the details, and he is driven to make whatever he is involved in the best that it can possibly be.</p>

<p>The people I work with at our company have consistently demonstrated some of the highest levels of excellence I have ever seen in this industry. The directors in our company are heroes to me: each of them contributes to the well-being and leadership of our company in different, complimentary ways, and they are some of the greatest people I have ever worked with. Michael will be joining us in our efforts to make it even easier for our team to rise above the rest, by pitching in where help is needed, removing obstacles as they occur, and providing leadership where the need arises.</p>

<p>As an Apple Evangelist, Michael has long been a well-known person in the development community. I am unbelievably happy that when he decided to join the community, he chose to join Black Pixel.</p>

<p>We couldn&#8217;t be more pleased to welcome Michael to our team.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Caching and NSURLConnection</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2012/05/caching-and-nsurlconnection.html" />
    <id>tag:new.blackpixel.com,2012:/blog//2.674</id>

    <published>2012-05-27T00:00:08Z</published>
    <updated>2012-11-18T04:28:06Z</updated>

    <summary>Shortly after the launch of the Mule Radio App we started to notice that episode lists weren&#8217;t refreshing as new...</summary>
    <author>
        <name>Daniel Pasco</name>
        
    </author>
    
        <category term="Posts" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p>Shortly after the launch of the <a href="http://muleradio.net">Mule Radio App</a> we started to notice that episode lists weren&#8217;t refreshing as new show audio was posted to the site. We hadn&#8217;t seen this during development and hadn&#8217;t really had a good opportunity to test this against the production server as new episodes went live before release, so we missed this behavior before the app shipped.</p>

<p>I had a hard time understanding why this was happening - we&#8217;ve shipped a lot of applications using NSURLConnection before and I hadn&#8217;t personally experienced this kind of thing before.</p>

<p>Here&#8217;s what I found out: it looks like NSURLConnection&#8217;s default cache policy may keep things around for a really, really long time if the web service you are talking to doesn&#8217;t specify a max age or content-expires header</p>

<h2>NSURLConnection&#8217;s Default Caching Policy</h2>

<p>When you use NSURLConnection without specifying a cache policy to use, <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLRequest_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSURLRequestUseProtocolCachePolicy">NSURLRequestUseProtocolCachePolicy</a> is used as the default.</p>

<p>The documentation for this is as follows</p>

<blockquote>
  <p>NSURLRequestUseProtocolCachePolicy Specifies that the caching logic defined in the protocol implementation, if any, is used for a particular URL load request. This is the default policy for URL load requests.</p>
</blockquote>

<p>That is actually totally accurate, but it&#8217;s not really clear what they&#8217;re saying. Here&#8217;s what the document &#8220;<a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Concepts/CachePolicies.html">Understanding Cache Access</a>&#8221; says</p>

<blockquote>
  <p>Cache Use Semantics for the http Protocol</p>

<p>The most complicated cache use situation is when a request uses the http protocol and has set the cache policy to NSURLRequestUseProtocolCachePolicy.</p>

<p>If an NSCachedURLResponse does not exist for the request, then the data is fetched from the originating source. If there is a cached response for the request, the URL loading system checks the response to determine if it specifies that the contents must be revalidated. If the contents must be revalidated a connection is made to the originating source to see if it has changed. If it has not changed, then the response is returned from the local cache. If it has changed, the data is fetched from the originating source.</p>

<p>If the cached response doesn&#8217;t specify that the contents must be revalidated, the maximum age or expiration specified in the response is examined. If the cached response is recent enough, then the response is returned from the >local cache. If the response is determined to be stale, the originating source is checked for newer data. If newer data is available, the data is fetched from the originating source, otherwise it is returned from the cache.</p>

<p><a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13">RFC 2616, Section 13</a> specifies the semantics involved in detail.</p>
</blockquote>

<p>So, in a nutshell, it says that the caching implementation looks at the response from the server to decide whether or not it should actually go and fetch the data again.</p>

<p>A field trip to the RFC mentioned revealed that what NSURLRequestUseProtocolCachePolicy actually does is look at the expiration headers returned along with the request for cues on how to handle caching. These cues come in the form of either an Expires: header or a Cache-Control: header with a max-age or s- maxage parameter.</p>

<p>All in all, this seems very sensible. Presumably the people that set up the server know what reasonable cache lifetimes are for their data, and this provides a way for applications to update their caching algorithms automatically, just by changing the values at the server. That&#8217;s nice.</p>

<h2>The part that bit us</h2>

<blockquote>
  <p>If none of Expires, Cache-Control: max-age, or Cache-Control: s- maxage (see section 14.9.3) appears in the response, and the response does not include other restrictions on caching, <strong>the cache MAY compute a freshness lifetime using a heuristic</strong>. The cache MUST attach Warning 113 to any response whose age is more than 24 hours if such warning has not already been added.</p>
</blockquote>

<p>It also reads</p>

<blockquote>
  <p>Also, if the response does have a Last-Modified time, the heuristic expiration value SHOULD be no more than some fraction of the interval since that time. A typical setting of this fraction might be 10%.</p>
</blockquote>

<p>So, if expiration information isn&#8217;t provided by the server, the client-side can figure out how to handle cache lifetimes itself. Apparently NSURLConnection caching logic does this by picking a rather large lifetime for the downloaded data. From our experience, I&#8217;d guess that the implementation being used for NSURLConnection is not using the 10% rule.</p>

<p><a href="http://openradar.appspot.com/radar?id=1755402">The problem is that Apple&#8217;s documentation doesn&#8217;t detail what it does when no cache policy is specified by the application and no expiration details are provided by the server</a>. It would be great if a default expiration period were listed in the documentation. At least one person has <a href="https://twitter.com/dougsillars/status/206575673588985856">suggested</a> that the default timeout should be 24 hours, according to the RFC. I saw a lot of things that suggested it, but nothing that struck me as hard evidence that this is the case here.</p>

<p>Fortunately, empirical evidence from pissed off users suggests that the expiration time is somewhere between 6 hours and a day.</p>

<p>Clearly, the answer in our case was to update the server to provide explicit expiration information. But that may not always be something you can influence when you&#8217;re developing an application to work with a third party service supplying time-sensitive information.</p>

<h2>How you can detect this and work around it in your application code</h2>

<p>So, if the default expiration time isn&#8217;t going to work for you, here&#8217;s some code that might get you started figuring out how to work around it.</p>

<pre class="brush: oc">
    - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {

        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)[cachedResponse response];

        // Look up the cache policy used in our request
        if([connection currentRequest].cachePolicy == NSURLRequestUseProtocolCachePolicy) {
            NSDictionary *headers = [httpResponse allHeaderFields];
            NSString *cacheControl = [headers valueForKey:@"Cache-Control"];
            NSString *expires = [headers valueForKey:@"Expires"];
            if((cacheControl == nil) && (expires == nil)) {
                NSLog(@"server does not provide expiration information and we are using NSURLRequestUseProtocolCachePolicy");
                return nil; // don't cache this
            }
        }
        return cachedResponse;
    }
</pre>

<p><code>- connection:willCacheResponse:</code> will get called whenever NSURLConnection has downloaded valid data and is about to save it to the cache. You can get a reference to the original request, and see what cache policy was used, and you can also inspect the headers returned by the server yourself.</p>

<p>If the cache policy is set to <code>NSURLRequestUseProtocolCachePolicy</code> and expiration data has been provided, this method will allow the cache to be saved, to be redownloaded the next time we make a request after the expiration period has passed. This method will also allow caching for any other applicable cache policy.</p>

<p>If there are no expiration-related headers in the response, and the cache policy is set to <code>NSURLRequestUseProtocolCachePolicy</code>, you should be able to intercede here if the default time interval is too long for your needs. </p>

<p>In this case, I simply return <code>nil</code>, which prevents the copy from being saved at all, which means that every time our app tries to download the data (and it tries at reasonable intervals already), it will get a fresh copy.</p>

<p>This could be more robust, for instance, the Cache-Control header might be present but not contain valid data, but it&#8217;s a starting point.</p>

<h2>Not all cache policies are actually implemented</h2>

<p>Although there is an <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLRequest_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSURLRequestUseProtocolCachePolicy">extensive list of different cache policies listed in the documentation</a>, at least a few of these policies are not actually implemented, or actually do something different than suggested.</p>

<p>Here&#8217;s what&#8217;s actually in NSURLRequest.h</p>

<pre class="brush: oc">
    enum
    {
        NSURLRequestUseProtocolCachePolicy = 0,

        NSURLRequestReloadIgnoringLocalCacheData = 1,
        NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented
        NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,

        NSURLRequestReturnCacheDataElseLoad = 2,
        NSURLRequestReturnCacheDataDontLoad = 3,

        NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented
    };
    typedef NSUInteger NSURLRequestCachePolicy;
</pre>

<p>I have opened a <a href="http://openradar.appspot.com/radar?id=1755401">radar</a> on this as well.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Unique Identifier Is Dead, Long Live Unique Identifier</title>
    <link rel="alternate" type="text/html" href="http://blackpixel.com/blog/2012/03/unique-identifier-is-dead-long-live-unique-identifier.html" />
    <id>tag:new.blackpixel.com,2012:/blog//2.673</id>

    <published>2012-03-13T21:46:37Z</published>
    <updated>2012-11-18T04:26:49Z</updated>

    <summary>As of iOS 5, Apple has deprecated the device unique identifier api and hasn&#8217;t provided a friendly Obj-C replacement, instead...</summary>
    <author>
        <name>Doug Russell</name>
        
    </author>
    
        <category term="Posts" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blackpixel.com/blog/">
        <![CDATA[<p>As of iOS 5, Apple has deprecated the device unique identifier api and hasn&#8217;t provided a friendly Obj-C replacement, instead recommending <a href="https://developer.apple.com/library/ios/#documentation/uikit/reference/UIDevice_Class/DeprecationAppendix/AppendixADeprecatedAPI.html">CFUUIDCreate and NSUserDefaults</a>.</p>

<p>CFUUIDCreate isn&#8217;t very complicated and neither is NSUserDefaults, but this solution fails in a few different ways:</p>

<ul>

<li>It&#8217;s not a quick one-shot call to get the UUID; you have to write your own wrapper to make it friendly</li>

<li>It doesn&#8217;t persist; deleting the app blows away the UUID</li>

<li>There&#8217;s no way to share it between apps</li>

</ul>

<p>The answer to these issues is to create a class that acts as the wrapper and improves on the persistence and sharing options using <a href="https://developer.apple.com/library/ios/#documentation/security/conceptual/keychainServConcepts/iPhoneTasks/iPhoneTasks.html#//apple_ref/doc/uid/TP30000897-CH208-SW1">Keychain</a>.</p>

<p>Quick Keychain primer:</p>

<blockquote>

  <p>On iOS each apps gets its own keychain where it can store sensitive data that only that app can access, with some very particular exceptions. This keychain is persisted across installations and, if the user encrypts their backups, across restores. A full restore and setup as a new device or restore from unencrypted backup wipes the keychain.</p>

</blockquote>

<p>This gives us a place to store an app (or app suite) specific UUID that will last as long as a given user continues using that device, but that will change if they do a full restore. That&#8217;s a nice level of fidelity that suits most legitimate tracking needs, like identifying that a device is already known to a web service tracking active devices. A given device won&#8217;t have two UUIDs simultaneously and for most users won&#8217;t change until they get a new device.</p>

<p>Another useful feature of Keychain is support for access groups, which allow iOS applications from the same provider to opt in to sharing a common keychain. The UUID can be stored in a keychain that all the apps can access, thus allowing us to know that a given set of installations all represent a single device.</p>

<blockquote>

  <p>&#8220;So this all seems interesting, but where&#8217;s the code?&#8221;

 - Nerds Still Reading This</p>

</blockquote>

<pre class="brush: oc">

 @interface BPXLUUIDHandler : NSObject

 /*

  * Retrieve UUID from keychain, if one does not exist, generate one and store it in the keychain.

  * UUIDs stored in the keychain will perisist across application installs

  * but not across device restores.

  */

 + (NSString *)UUID;

 /*

  * Remove stored UUID from keychain

  /

 + (void)reset;

 /*

  * Getter/setter for access group used for reading/writing from keychain.

  * Useful for shared keychain access across applications with the

  * same bundle seed (requires properly configured provisioning and entitlements)

  */

 + (NSString *)accessGroup;

 + (void)setAccessGroup:(NSString *)accessGroup;

 @end

</pre>

<p>BPXLUUIDHandler is a class we created to encapsulate all the handling of getting/storing the new UUID and added support for access groups since some of our clients have application suites.</p>

<p>It supports ARC and non ARC configurations and tucks away all the keychain interaction so that we don&#8217;t have to keep writing the same blob of keychain queries again and again.</p>

<p>It&#8217;s available for download at our <a href="https://github.com/blackpixel/BPXLUUIDHandler">github</a>, use and enjoy and provide feedback.</p>
]]>
        

    </content>
</entry>

</feed>
