list.her.sh 2023-04-07T02:58:05+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>xcodebuild</code> versions using the <code>xcode-select --switch</code> command-line utility. But this requires <code>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>xcode-select</code>! The trick is twofold: assign a value to the <code>DEVELOPER_DIR</code> environment variable and run your build with <code>xcrun</code>.</p> <p>I standardize my build commands with <code>rake</code> tasks. Here’s a <code>rake test</code> task you might use, perhaps in your <code>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>.travis.yml</code></a> and <a href="https://github.com/splinesoft/SPLUserActivity/blob/master/circle.yml"><code>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>Gemfile</code> or as a <a href="https://github.com/IFTTT/JazzHands/blob/master/.travis.yml#L3">dependency command</a> in your <code>.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>.travis.yml</code> a line like <code>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>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>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>xcodebuild</code> in the <a href="https://github.com/IFTTT/JazzHands/blob/master/.travis.yml#L10">build command</a> in your <code>.travis.yml</code> or <code>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>.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>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>CGFloat</code> type previously aliased to <code>float</code> newly redefined as <code>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>CGFloat</code> type for the current device’s architecture. You’ll also want to use the correct <code>float</code> or <code>double</code> versions of math functions like <code>floor</code> (double) or <code>floorf</code> (float).</p> <p>Thanks to some preprocessor magic and the <code>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>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>tgmath.h</code></a>, though it must be included before <code>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> <thead> <tr> <th style="text-align: left"> </th> <th style="text-align: left"> </th> </tr> </thead> <tbody> <tr> <td style="text-align: left"><img src="/img/mr-dev.png" width="90" height="90" alt="MUDRammer Debug" /></td> <td style="text-align: left">  Debug</td> </tr> <tr> <td style="text-align: left"><img src="/img/mr-adhoc.png" width="90" height="90" alt="MUDRammer Adhoc/Beta" /></td> <td style="text-align: left">  Adhoc/Beta</td> </tr> <tr> <td style="text-align: left"><img src="/img/mr-release.png" width="90" height="90" alt="MUDRammer Release" /></td> <td style="text-align: left">  Release</td> </tr> </tbody> </table> <p>Start by adding one or two new App Icon image sets to your asset catalog: click the <code>+</code> in your asset catalog → <code>New App Icon</code>. (Your app doesn’t use an asset catalog? Xcode will create one for you on your project’s <code>General</code> tab. Go ahead, I’ll wait.)</p> <p>Give your new App Icon image sets some memorable names. Mine are <code>AppIconRelease</code>, <code>AppIconAdhoc</code>, and <code>AppIconDebug</code>.</p> <p>In your application target’s build settings, scroll down to <code>Asset Catalog Compiler - Options</code> and expand the arrow next to <code>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>