list.her.sh 2024-12-04T05:07:18+00:00 https://list.her.sh Jonathan Hersh jon@her.sh The right xcodebuild at the right time 2015-06-13T00:00:00+00:00 https://list.her.sh/which-xcodebuild <p>What an incredible WWDC! You’ve probably been checking out the new bits and you’ve collected several versions of Xcode on your machine.</p> <p>Traditionally, you’d switch active <code class="language-plaintext highlighter-rouge">xcodebuild</code> versions using the <code class="language-plaintext highlighter-rouge">xcode-select --switch</code> command-line utility. But this requires <code class="language-plaintext highlighter-rouge">sudo</code> and switches the active developer directory system-wide, both of which can be undesirable particularly for CI builds.</p> <p>It turns out you can specify a per-build developer directory on the command line without <code class="language-plaintext highlighter-rouge">xcode-select</code>! The trick is twofold: assign a value to the <code class="language-plaintext highlighter-rouge">DEVELOPER_DIR</code> environment variable and run your build with <code class="language-plaintext highlighter-rouge">xcrun</code>.</p> <p>I standardize my build commands with <code class="language-plaintext highlighter-rouge">rake</code> tasks. Here’s a <code class="language-plaintext highlighter-rouge">rake test</code> task you might use, perhaps in your <code class="language-plaintext highlighter-rouge">xcode-7</code> branch, to execute a single build using an alternate Xcode:</p> <figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">desc</span> <span class="s1">'Run all application tests.'</span> <span class="n">task</span> <span class="ss">:test</span> <span class="k">do</span> <span class="n">dev_dir</span> <span class="o">=</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'DEVELOPER_DIR'</span><span class="p">]</span> <span class="o">||</span> <span class="s2">""</span> <span class="c1"># Path to desired Xcode beta</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'DEVELOPER_DIR'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'/Applications/Xcode-beta.app/Contents/Developer'</span> <span class="n">sh</span> <span class="s2">"set -o pipefail &amp;&amp; xcrun -sdk iphonesimulator "</span><span class="o">+</span> <span class="s2">"xcodebuild ... etc ... "</span><span class="o">+</span> <span class="s2">"clean test | bundle exec xcpretty -ct"</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'DEVELOPER_DIR'</span><span class="p">]</span> <span class="o">=</span> <span class="n">dev_dir</span> <span class="k">end</span></code></pre></figure> iOS Test Coverage with Coveralls 2015-03-11T00:00:00+00:00 https://list.her.sh/ios-test-coverage-with-coveralls <p>Code coverage measures how much of your app or library is executed by at least one of your tests. This manifests as a percentage from 0-100% that can be a good high-level indicator of the quality — or at least the breadth — of your tests.</p> <p>Today we’ll see how easy it is to automatically measure, report, and visualize code coverage in your iOS app or library. You’ll end up with a report <a href="https://coveralls.io/builds/1975865">like this one</a> for each file in your project and a great visual representation showing line-by-line where your coverage is strong, where you can improve, and how your coverage trends up (or down!) over time.</p> <p>You will need:</p> <ol> <li>An iOS app or library to test</li> <li>Some tests to execute against your app or library</li> <li>A CI service that executes your tests, like <a href="https://travis-ci.org">Travis CI</a> or <a href="https://circleci.com">CircleCI</a>, both of which are free for open-source projects</li> <li>A code coverage tool like <a href="https://coveralls.io">Coveralls</a> that can visualize your code coverage results. Coveralls is free for open-source projects!</li> <li>A utility like <a href="https://github.com/venmo/slather">slather</a> that sends your test code coverage results from your CI service (#3) to your code coverage tool (#4) every time your CI service runs your tests</li> </ol> <p><a href="https://github.com/splinesoft/SSDataSources">SSDataSources</a>, <a href="https://github.com/IFTTT/JazzHands">Jazz Hands</a>, <a href="https://github.com/IFTTT/FastttCamera">FastttCamera</a>, and <a href="https://github.com/IFTTT/IFTTTLaunchImage">IFTTTLaunchImage</a> are great examples of open-source iOS projects that report code coverage with Travis CI, Coveralls, and slather. As of this writing, slather does not yet support CircleCI, but work is <a href="https://github.com/venmo/slather/pull/55">in progress</a> and SSDataSources is <a href="https://github.com/splinesoft/SSDataSources/pull/49">nearly there</a>. <strong>Update:</strong> slather now supports CircleCI and SSDataSources now builds on CircleCI with slather!</p> <p>First, you’ll need to get CI to run your project’s tests each time you push a commit. See the <a href="http://docs.travis-ci.com/user/languages/objective-c/">Travis CI iOS docs</a> and <a href="https://circleci.com/docs/ios-builds-on-os-x/">CircleCI iOS docs</a>, or perhaps you’ll be inspired by these <a href="https://github.com/IFTTT/JazzHands/blob/master/.travis.yml"><code class="language-plaintext highlighter-rouge">.travis.yml</code></a> and <a href="https://github.com/splinesoft/SPLUserActivity/blob/master/circle.yml"><code class="language-plaintext highlighter-rouge">circle.yml</code></a> files from the above projects.</p> <p>Now you’ll need to add the <a href="https://github.com/venmo/slather">slather</a> rubygem to your project. You don’t necessarily need slather installed locally on your development machine; rather, you could include it in your project’s <code class="language-plaintext highlighter-rouge">Gemfile</code> or as a <a href="https://github.com/IFTTT/JazzHands/blob/master/.travis.yml#L3">dependency command</a> in your <code class="language-plaintext highlighter-rouge">.travis.yml</code>. You’ll also need to instruct your CI service to execute slather after a successful build: for Travis CI, you might add to your <code class="language-plaintext highlighter-rouge">.travis.yml</code> a line like <code class="language-plaintext highlighter-rouge">after_success: slather</code>.</p> <p>You’ll need to update some build settings in your project so that when your project’s tests are run, <code class="language-plaintext highlighter-rouge">xcodebuild</code> will measure the code paths that are executed by your tests and generate a file that code coverage utilities can parse for coverage results.</p> <p>There are three ways to set this up. Pick your favorite:</p> <ol> <li>If you have slather installed on your development machine, you can execute <code class="language-plaintext highlighter-rouge">slather setup path/to/project.xcodeproj</code> to enable the necessary settings in your Xcode project.</li> <li>If you don’t have slather locally, head to the “Build Settings” tab of your Xcode project, scroll down to the “Code Generation” section, and set to YES these two settings for the scheme(s) and configuration(s) that your tests will execute: <strong>Generate Test Coverage Files</strong> and <strong>Instrument Program Flow</strong>.</li> <li>You could update the flags passed to <code class="language-plaintext highlighter-rouge">xcodebuild</code> in the <a href="https://github.com/IFTTT/JazzHands/blob/master/.travis.yml#L10">build command</a> in your <code class="language-plaintext highlighter-rouge">.travis.yml</code> or <code class="language-plaintext highlighter-rouge">circle.yml</code> to add:</li> </ol> <figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">GCC_INSTRUMENT_PROGRAM_FLOW_ARCS</span><span class="o">=</span>YES <span class="nv">GCC_GENERATE_TEST_COVERAGE_FILES</span><span class="o">=</span>YES</code></pre></figure> <p>You might consider updating your CI script’s build flags (#3 above) even in addition to #1 or #2 to be extra certain that your CI service is generating code coverage files for every build.</p> <p>Next, head to <a href="https://coveralls.io">Coveralls</a>, sign in with your Github user, and add your repo to Coveralls.</p> <p>Your project will also need a simple <code class="language-plaintext highlighter-rouge">.slather.yml</code> file in the root of your repo. This instructs slather how to process your code coverage results and where to send them. Here is one of mine, for use in a Travis CI project:</p> <figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">ci_service</span><span class="pi">:</span> <span class="s">travis_ci</span> <span class="na">coverage_service</span><span class="pi">:</span> <span class="s">coveralls</span> <span class="na">xcodeproj</span><span class="pi">:</span> <span class="s">Example/ExampleSSDataSources.xcodeproj</span> <span class="na">source_directory</span><span class="pi">:</span> <span class="s">SSDataSources</span></code></pre></figure> <p>Of particular note for CocoaPods repos is the <code class="language-plaintext highlighter-rouge">source_directory</code> parameter. Here you can specify exactly which files should be included in your code coverage results — this is necessary so that you can measure only the files in your pod and exclude source files that might be in a sample or demo project.</p> <p>That’s it! Package up a commit with your changes, send it via carrier pigeon to Github, and — if your build succeeds — you should see your very first coverage report on Coveralls.</p> CGFloat in a 64-bit world 2014-10-10T00:00:00+00:00 https://list.her.sh/cgfloat-and-arm64 <p>Apple’s A7 chip famously moved to a 64-bit architecture. This ushered in an era of access to more memory* and a <code class="language-plaintext highlighter-rouge">CGFloat</code> type previously aliased to <code class="language-plaintext highlighter-rouge">float</code> newly redefined as <code class="language-plaintext highlighter-rouge">double</code>. Wait, what?</p> <p>If you’re writing an iOS app that targets multiple architectures, you’ll want to use the proper <code class="language-plaintext highlighter-rouge">CGFloat</code> type for the current device’s architecture. You’ll also want to use the correct <code class="language-plaintext highlighter-rouge">float</code> or <code class="language-plaintext highlighter-rouge">double</code> versions of math functions like <code class="language-plaintext highlighter-rouge">floor</code> (double) or <code class="language-plaintext highlighter-rouge">floorf</code> (float).</p> <p>Thanks to some preprocessor magic and the <code class="language-plaintext highlighter-rouge">CGFLOAT_IS_DOUBLE</code> define, we can construct some helpers that call the correct math function and return a number of the correct type for the current architecture. Behold, <code class="language-plaintext highlighter-rouge">SPLFloat.h</code>!</p> <p><strong>Update:</strong> One alternative to the below is <a href="http://pubs.opengroup.org/onlinepubs/009695399/basedefs/tgmath.h.html"><code class="language-plaintext highlighter-rouge">tgmath.h</code></a>, though it must be included before <code class="language-plaintext highlighter-rouge">math.h</code>. That can be challenging if you’re using CocoaPods.</p> <figure class="highlight"><pre><code class="language-objc" data-lang="objc"><span class="c1">// SPLFloat.h</span> <span class="k">@import</span> <span class="n">Foundation</span><span class="p">;</span> <span class="cp">#pragma once </span> <span class="n">CG_INLINE</span> <span class="n">CGFLOAT_TYPE</span> <span class="nf">SPLFloat_floor</span><span class="p">(</span><span class="n">CGFLOAT_TYPE</span> <span class="n">cgfloat</span><span class="p">)</span> <span class="p">{</span> <span class="cp">#if CGFLOAT_IS_DOUBLE </span> <span class="k">return</span> <span class="n">floor</span><span class="p">(</span><span class="n">cgfloat</span><span class="p">);</span> <span class="cp">#else </span> <span class="k">return</span> <span class="n">floorf</span><span class="p">(</span><span class="n">cgfloat</span><span class="p">);</span> <span class="cp">#endif </span><span class="p">}</span> <span class="n">CG_INLINE</span> <span class="n">CGFLOAT_TYPE</span> <span class="nf">SPLFloat_ceil</span><span class="p">(</span><span class="n">CGFLOAT_TYPE</span> <span class="n">cgfloat</span><span class="p">)</span> <span class="p">{</span> <span class="cp">#if CGFLOAT_IS_DOUBLE </span> <span class="k">return</span> <span class="n">ceil</span><span class="p">(</span><span class="n">cgfloat</span><span class="p">);</span> <span class="cp">#else </span> <span class="k">return</span> <span class="n">ceilf</span><span class="p">(</span><span class="n">cgfloat</span><span class="p">);</span> <span class="cp">#endif </span><span class="p">}</span> <span class="n">CG_INLINE</span> <span class="n">CGFLOAT_TYPE</span> <span class="nf">SPLFloat_round</span><span class="p">(</span><span class="n">CGFLOAT_TYPE</span> <span class="n">cgfloat</span><span class="p">)</span> <span class="p">{</span> <span class="cp">#if CGFLOAT_IS_DOUBLE </span> <span class="k">return</span> <span class="n">round</span><span class="p">(</span><span class="n">cgfloat</span><span class="p">);</span> <span class="cp">#else </span> <span class="k">return</span> <span class="n">roundf</span><span class="p">(</span><span class="n">cgfloat</span><span class="p">);</span> <span class="cp">#endif </span><span class="p">}</span> <span class="n">CG_INLINE</span> <span class="n">CGFLOAT_TYPE</span> <span class="nf">SPLFloat_abs</span><span class="p">(</span><span class="n">CGFLOAT_TYPE</span> <span class="n">cgfloat</span><span class="p">)</span> <span class="p">{</span> <span class="cp">#if CGFLOAT_IS_DOUBLE </span> <span class="k">return</span> <span class="n">fabs</span><span class="p">(</span><span class="n">cgfloat</span><span class="p">);</span> <span class="cp">#else </span> <span class="k">return</span> <span class="n">fabsf</span><span class="p">(</span><span class="n">cgfloat</span><span class="p">);</span> <span class="cp">#endif </span><span class="p">}</span> <span class="n">CG_INLINE</span> <span class="n">CGFLOAT_TYPE</span> <span class="nf">SPLFloat_pow</span><span class="p">(</span><span class="n">CGFLOAT_TYPE</span> <span class="n">cgfloat</span><span class="p">,</span> <span class="n">CGFLOAT_TYPE</span> <span class="n">exp</span><span class="p">)</span> <span class="p">{</span> <span class="cp">#if CGFLOAT_IS_DOUBLE </span> <span class="k">return</span> <span class="n">pow</span><span class="p">(</span><span class="n">cgfloat</span><span class="p">,</span> <span class="n">exp</span><span class="p">);</span> <span class="cp">#else </span> <span class="k">return</span> <span class="n">powf</span><span class="p">(</span><span class="n">cgfloat</span><span class="p">,</span> <span class="n">exp</span><span class="p">);</span> <span class="cp">#endif </span><span class="p">}</span></code></pre></figure> <p><br /> * My kingdom for an iPhone with more than 1GB RAM.</p> Beta iOS App Icons 2014-09-30T00:00:00+00:00 https://list.her.sh/app-icons <p>If you’re constantly switching between Debug, Adhoc/Beta, and Release builds of your app, it can be very helpful to have unique app icons for each configuration. You can easily tell at a glance which version is installed, your beta testers send you better feedback, a lasting world peace takes hold — everyone wins! Best of all, with Xcode 5+’s asset catalogs, there’s no code required.</p> <p>Here’s how this looks in my app <a href="https://itunes.apple.com/us/app/mudrammer-a-modern-mud-client/id597157072?mt=8">MUDRammer - A Modern MUD Client</a>:</p> <table> <tbody> <tr> <td><img src="/img/mr-dev.png" width="90" height="90" alt="MUDRammer Debug" /></td> <td>  Debug</td> </tr> <tr> <td><img src="/img/mr-adhoc.png" width="90" height="90" alt="MUDRammer Adhoc/Beta" /></td> <td>  Adhoc/Beta</td> </tr> <tr> <td><img src="/img/mr-release.png" width="90" height="90" alt="MUDRammer Release" /></td> <td>  Release</td> </tr> </tbody> </table> <p>Start by adding one or two new App Icon image sets to your asset catalog: click the <code class="language-plaintext highlighter-rouge">+</code> in your asset catalog → <code class="language-plaintext highlighter-rouge">New App Icon</code>. (Your app doesn’t use an asset catalog? Xcode will create one for you on your project’s <code class="language-plaintext highlighter-rouge">General</code> tab. Go ahead, I’ll wait.)</p> <p>Give your new App Icon image sets some memorable names. Mine are <code class="language-plaintext highlighter-rouge">AppIconRelease</code>, <code class="language-plaintext highlighter-rouge">AppIconAdhoc</code>, and <code class="language-plaintext highlighter-rouge">AppIconDebug</code>.</p> <p>In your application target’s build settings, scroll down to <code class="language-plaintext highlighter-rouge">Asset Catalog Compiler - Options</code> and expand the arrow next to <code class="language-plaintext highlighter-rouge">Asset Catalog App Icon Set Name</code>. By default, you’ll see the same App Icon set for all of your app’s configurations. Now it’s just a matter of assigning your App Icon set names to the proper configurations for your app.</p> <p>Here’s some caution tape. Be careful out there!</p> <p><img src="/img/caution-tape.png" alt="DANGER" /></p> <p>For bonus points, start continuously integrating your iOS app. Here’s <a href="https://github.com/splinesoft/SSBuild">my build script</a>!</p> One Star 2014-01-09T00:00:00+00:00 https://list.her.sh/one-star <p><img src="/img/onestar.png" alt="One Star" /></p> <h3 id="one-star-2014"><em>One Star</em> (2014)</h3> <p>Mixed Media (iTunes, <a href="http://flyingmeat.com/acorn/">Acorn</a>)</p> On a dark dessert highway 2012-10-15T00:00:00+00:00 https://list.her.sh/on-a-dark-dessert-highway <p>On a dark dessert highway, Cool Whip® in my hair<br /> Warm smell of carnitas rising up through the air<br /> Up ahead in the distance, I smell some sizzling fries<br /> My stomach rumbled – it needs glycogen!<br /> I just had to supersize</p> <p>Hostess stands in the doorway, I heard the taco bell<br /> I was thinking to myself, “This could be heaven or calorie hell!”<br /> Then she holds up a Twinkie® and she throws it my way<br /> Creamy filling hits my uvula<br /> Like a fine soufflé</p> <p>Welcome to the Hostess® Cafeteria<br /> Sugar-coated plates (syrup on your face)<br /> Salad’s a disgrace<br /> For any olfactory criteria<br /> Fourteen kinds of beer (one by Richard Gere)<br /> Bagels served with smear</p> <p>She loves her froyo twisted, with sprinkles she recommends<br /> She got a lot of tall, hirsute garçons she calls “Franz!”<br /> See them push the dessert cart – sweet Crêpes Suzette!<br /> Some served from a blender, some <em>avec baguette</em></p> <p>So I tackled a garçon,<br /> “CHOCOLATE NOW MINE!”<br /> He screamed, “There’s some kind of lunatic here lying down on my spine!”<br /> Still got some morsels of tasty créme brûlée<br /> Eat ‘em up in the middle of a Skype<br /> With a large latte…</p> <p><em>with apologies to D. Felder, D. Henley, and G. Frey</em></p> hello world 2012-10-14T00:00:00+00:00 https://list.her.sh/hello <p><a href="http://jsomers.net/blog/more-people-should-write">More people should write.</a> I’m trying (again) to be one of them.</p>