App-o-Mat Bloghttps://app-o-mat.com/posts/2020-04-23T11:58:54+00:00Latest App-o-Mat blog posts.The Swift Programming Language Companion: Section 12020-04-23T11:58:54+00:00https://app-o-mat.com/post/swift-programming-language-companion-section-1<p>In my last article I explained that aspiring iOS App Developers should <a href="https://app-o-mat.com/post/start-with-swift">start by learning swift</a> and not jump into app tutorials.</p>
<blockquote>
<p>Before you learn about <code>UIViewController</code>, <code>UITableViewDataSource</code>, and <code>NSManagedObject</code>, you need to fully understand <code>let</code>, <code>var</code>, <code>enum</code>, <code>struct</code>, <code>if</code>, <code>for in</code>, <code>case let</code>, and <code>guard let</code>.</p>
<p>So, if you know no Swift at all and don't know a similar programming language, start with Apple's Swift Programming Language book and Swift playgrounds (on the iPad or in Xcode on a Mac). Learn how to write extremely simple functions and then small sets of structs/classes that work together.</p>
</blockquote>
<p>It’s important to not just read the book and type in the code you see in it. You should actively write new code based on what you learned</p>
<p>To help, I’ve been working on a series of articles meant to be read after each corresponding chapter in the Swift Programming Language book. Each article has a few exercises that you should be able to do in a playground based on the information in the chapter.</p>
<p>I also show a way to set up an active reading environment and a method for generating exercises on your own if you need to go beyond what I have provided.</p>
<p>There are eleven articles so far, I recommend reading them in order and doing the exercises (because they build on each other). If you know a topic well, it will just take a few minutes to get through them. They are meant to take about 30 minutes for a brand new programmer studying Swift as a first language.</p>
<h2>Section 1</h2>
<ol>
<li><a href="https://app-o-mat.com/article/swift-companion/introduction">Introduction</a></li>
<li><a href="https://dev.to/loufranco/the-swift-programming-language-companion-the-basics-3kd7">The Basics</a></li>
<li><a href="https://dev.to/loufranco/the-swift-programming-language-companion-optionals-1p1h">Optionals</a></li>
<li><a href="https://dev.to/loufranco/the-swift-programming-language-companion-basic-operators-37d">Basic Operators</a></li>
<li><a href="https://dev.to/loufranco/the-swift-programming-language-companion-strings-and-characters-2gie">Strings and Characters</a></li>
<li><a href="https://dev.to/loufranco/the-swift-programming-language-companion-collection-types-2kko">Collection Types</a></li>
<li><a href="https://dev.to/loufranco/the-swift-programming-language-companion-control-flow-2p84">Control Flow</a></li>
<li><a href="https://dev.to/loufranco/the-swift-programming-language-companion-functions-446j">Functions</a></li>
<li><a href="https://dev.to/loufranco/the-swift-programming-language-companion-functions-part-2-329k">Functions (Part 2)</a></li>
<li><a href="https://dev.to/loufranco/the-swift-programming-language-companion-review-of-basics-to-functions-359">Review of Basics to Functions</a></li>
<li><a href="https://dev.to/loufranco/the-swift-programming-language-companion-review-of-basics-to-functions-part-2-31k8">Review of Basics to Functions (Part 2)</a></li>
</ol>
<p>I’ll be starting on Section 2 now, so you could <a href="https://dev.to/loufranco">follow me on dev.to</a> if you want to see the articles as they publish.</p>Want to make an iOS App? Start with Swift2019-08-05T12:30:19+00:00https://app-o-mat.com/post/start-with-swift<p>The biggest obstacle I see in new app developers is that they struggle with the basics.</p>
<p>Before you learn about <code>UIViewController</code>, <code>UITableViewDataSource</code>, and <code>NSManagedObject</code>, you need to fully understand <code>let</code>. <code>var</code>, <code>enum</code>, <code>struct</code>, <code>if</code>, <code>for</code> <code>in</code>, <code>case let</code>, and <code>guard let</code>.</p>
<p>So, if you know no Swift at all and don't know a similar programming language, start with Apple's <a href="https://docs.swift.org/swift-book/index.html">Swift Programming Language</a> book and Swift playgrounds (on the iPad or in Xcode on a Mac). Learn how to write extremely simple functions and then small sets of structs/classes that work together.</p>
<p>In Apple's book, I would say to at least get through these chapters</p>
<ol>
<li>The Basics: If you are brand new, give it read, but realize that some of the topics might be beyond your grasp right now. Come back to it periodically.</li>
<li>Basic Operators</li>
<li>Strings and Characters</li>
<li>Collection Types</li>
<li>Control Flow</li>
<li>Functions</li>
<li>Closures</li>
<li>Enumeration</li>
<li>Structures and Classes</li>
<li>Properties</li>
<li>Methods</li>
</ol>
<p>This is enough to get started. But even the simplest <em>real</em> app is going to have <strong>Optional Chaining</strong>, <strong>Inheritance</strong>, and <strong>Protocols</strong>. If you run into something you haven't seen yet, find the chapter where it is discussed.</p>
<p>Then, once you capable of writing small functions on your own, take a look at simple step-by-step app tutorials.</p>The iOS/Android Job Market: 2019 Update2019-04-23T12:30:53+00:00https://app-o-mat.com/post/ios-android-job-market-2019-update<p><a href="/post/ios-android-mobile-dev-market-snapshot">Last year I wrote about the native mobile app developer job market</a> to answer the question: Should you know iOS-only, Android-only, or both. My conclusion was that:</p>
<blockquote>
<p>[...] there are more jobs that require both, but still enough of a market to specialize if you want to.</p>
</blockquote>
<p>and </p>
<blockquote>
<p>Remember that even a little experience in your non-dominant platform would open up more of those cross-platform jobs, as I am sure the minimum requirement is a huge range. Meaning, if you were a very advanced iOS developer, and had 6 months of Android, you could reasonably apply to many jobs that require both.</p>
</blockquote>
<p>So, knowing both is a little better, but not a requirement. I decided to see if anything changed a year later. You can see my full methodology on the original post.</p>
<h2>StackOverflow Jobs</h2>
<table>
<thead>
<tr>
<th>Year</th>
<th>Tagged<br/>iOS only</th>
<th>Tagged<br/>Android only</th>
<th>Tagged<br/>iOS/Android</th>
<th>Mentioned<br/>iOS/Android</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="/post/ios-android-mobile-dev-market-snapshot">2018</a></td>
<td>59</td>
<td>61</td>
<td>42</td>
<td>363</td>
</tr>
<tr>
<td>2019</td>
<td><a href="https://stackoverflow.com/jobs?q=%5bios%5d+-%5bandroid%5d&rs=1&sort=p">102</a></td>
<td><a href="https://stackoverflow.com/jobs?q=-%5bios%5d+%5bandroid%5d&rs=1&sort=p">159</a></td>
<td><a href="https://stackoverflow.com/jobs?q=%5bios%5d+%5bandroid%5d&rs=1&sort=p">80</a></td>
<td><a href="https://stackoverflow.com/jobs?sort=p&q=ios+android">784</a></td>
</tr>
</tbody>
</table>
<p>I believe that the increase in numbers is a combination of the market size and StackOverflow's ability to get listings, so I wouldn't read too much into the increase. The more important thing is that the ratio stayed in line to what we saw last year. The percent of jobs mentioning both platforms that say they require both went from 12% in 2018 to 10% in 2019.</p>
<h2>Indeed</h2>
<table>
<thead>
<tr>
<th>Year</th>
<th>Title has<br/>iOS only</th>
<th>Title has<br/>Android only</th>
<th>Title has<br/>iOS/Android</th>
<th>Title has Mobile<br/>Mentioned<br/>iOS/Android</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="/post/ios-android-mobile-dev-market-snapshot">2018</a></td>
<td>156</td>
<td>211</td>
<td>17</td>
<td>197</td>
</tr>
<tr>
<td>2019</td>
<td><a href="https://www.indeed.com/jobs?as_and=&as_phr=&as_any=&as_not=android&as_ttl=ios&as_cmp=&jt=all&st=&salary=&l=&fromage=7&limit=10&sort=&psf=advsrch">112</a></td>
<td><a href="https://www.indeed.com/jobs?as_and=&as_phr=&as_any=&as_not=ios&as_ttl=android&as_cmp=&jt=all&st=&salary=&fromage=7&limit=10&sort=&psf=advsrch">129</a></td>
<td><a href="https://www.indeed.com/jobs?as_and=&as_phr=&as_any=&as_ttl=android+ios&as_cmp=&jt=all&st=&salary=&fromage=7&limit=10&sort=&psf=advsrch">14</a></td>
<td><a href="https://www.indeed.com/jobs?as_and=ios+android&as_phr=&as_any=&as_not=&as_ttl=mobile&as_cmp=&jt=all&st=&salary=&l=&fromage=7&limit=10&sort=&psf=advsrch">157</a></td>
</tr>
</tbody>
</table>
<p>Fewer jobs in all categories, but again, this might have more to do with Indeed market-share. The important thing is the ratio. Like last year, there's an edge to knowing both, but either platform is viable on its own.</p>
<p>Also, like I said last year, competing to get a platform-specific job is easier if you specialize in that platform. This is especially true at the more senior levels. So, all of that time spent learning another platform would be better spent on becoming more of an expert in a single one.</p>
<p>But, if you want to know both, there is clearly a market for that too. I just would not add the iOS-only to the iOS/Android numbers and expect that the market is twice as big if you know both. The truth is somewhere in-between.</p>
<h2>Dice</h2>
<table>
<thead>
<tr>
<th>Year</th>
<th>Title has<br/>iOS only</th>
<th>Title has<br/>Android only</th>
<th>Title has<br/>iOS/Android</th>
<th>Title has Mobile<br/>Mentioned<br/>iOS/Android</th>
<th>Mentioned<br/>iOS/Android</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="/post/ios-android-mobile-dev-market-snapshot">2018</a></td>
<td>320</td>
<td>327</td>
<td>10</td>
<td>405</td>
<td>2,797</td>
</tr>
<tr>
<td>2019</td>
<td><a href="https://www.dice.com/jobs/advancedResult.html?for_one=&for_all=&for_exact=&for_none=android&for_jt=ios&for_com=&for_loc=&sort=date">232</a></td>
<td><a href="https://www.dice.com/jobs?q=-ios+title%3A%28android%29&l=">329</a></td>
<td><a href="https://www.dice.com/jobs?q=title%3A%28ios+android%29&l=">13</a></td>
<td><a href="https://www.dice.com/jobs?q=ios+android+title%3A%28mobile%29&l=">416</a></td>
<td><a href="https://www.dice.com/jobs?q=ios+android&l=">2,648</a></td>
</tr>
</tbody>
</table>
<p>Like last year, Dice is the one site I checked where the mixed iOS/Android market seems significantly bigger. The right-most three columns give different pictures. To interpret</p>
<ul>
<li>13 jobs have iOS and Android in the title of the position</li>
<li>416 have mobile in the title and mention both iOS and Android in the job description</li>
<li>2,648 mention both iOS and Android in the job description</li>
<li>1,532 is the average of the last two columns</li>
</ul>
<h2>Conclusions</h2>
<ul>
<li>The iOS/Android market is bigger than either platform. The effect is most pronounced on Dice, but since Dice is a very widely used site with primarily developer jobs, it is likely that this is representative. I would not say the same for Indeed (many non-developer jobs) and the dataset from SO is significantly smaller.</li>
<li>Each platform is also a viable market, so while knowing both is better, it's not required</li>
<li>If we apply StackOverflow's job tagging rate (10%) as a measure of "requirement" we would reduce the both-platforms number for Dice to 264 -- which I interpret as:<ul>
<li>Jobs that mentions both might not <em>require</em> expertise in both</li>
<li>There are some developer jobs that might just want familiarity with mobile (e.g. a devops position for the back-end of a mobile app)</li>
</ul>
</li>
</ul>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
$(".container table").addClass("table table-striped");
$(".container table thead").addClass("thead-dark");
$(".container table th").attr("scope", "col");
});
</script>Does Objective-C Block Syntax Make F'n Sense?2018-03-27T23:34:57+00:00https://app-o-mat.com/post/objective-c-block-syntax<p>You know the feeling. You're refactoring that old ViewController that’s still in Objective-C, and you get to that part where you need to extract an async call to a new class. You’ve gotten so used to closures in Swift that you're using them instead of delegates, even in Objective-C. And you say to yourself, “I know—I’ll use a block.”</p>
<p>Now you have two problems.</p>
<p>But no worries, because every Objective-C developer knows to go to <a href="http://fuckingblocksyntax.com/">F'n Block Syntax</a> to look up block syntax, because, well, block syntax is F'd. Even after you’ve looked it up, it doesn’t stick. But I remember at one time thinking it kind of made sense, so I tried to reconstruct my understanding.</p>
<p>Before I was doing iOS, I was mostly a C/C++ developer, and even though the syntax for types can be complex (especially with pointers), I did find it to be consistent. C pointer-to-function syntax was <em>probably</em> the basis of Objective-C block syntax, so it’s worth taking a look.</p>
<p>To start, a C function declaration looks like this:</p>
<pre><code>int add_ints(int x, int y)
</code></pre>
<p>This reads as: “add_ints is a function that takes two ints and returns an int.” The type of the "pointer to this function", if you wanted to assign a variable to it, is:</p>
<pre><code>int (*)(int x, int y)
</code></pre>
<p>Essentially, you just replace the name with a <code>*</code>, but it needs to be in parentheses because of operator precedence and associativity. In C, the <code>*</code> would associate with the <code>int</code> and change the return type to <code>int *</code>.</p>
<p>The weird part comes when you want to declare a variable with this type. To make it as close as possible to a function declaration, we want the name between the return type and the parameters. And it turns out, we want the <code>*</code> to associate with that name, so we put it inside the parens, like so:</p>
<pre><code>int (*func_ptr_variable)(int, int) = &add_ints;
</code></pre>
<p>The only thing that Objective-C did to this syntax is swap a <code>^</code> for the <code>*</code> to make a special operator to use for blocks (and break the association to pointers). </p>
<p>So, the equivalent variable declaration is:</p>
<pre><code>int (^block_variable)(int, int)
</code></pre>
<p>So, one way to remember this is to base the declaration on C style functions (like <code>return name(params)</code>) and to think of the <code>^</code> as a replacement for C’s <code>*</code> for blocks, and then to use parentheses to associate it with the "name".</p>
<p>When you want to pass a block to a method, you just need to remember that Objective-C method syntax always puts parentheses around the parameter type and the name outside the close paren, so it always looks like:</p>
<pre><code>-(void)doBlock:(typename)block_param
</code></pre>
<p>Where <code>typename</code> is <code>return (^)(params)</code>, so</p>
<pre><code>-(void)doBlock:(int (^)(int, int))block_param
</code></pre>
<p>If it starts getting more complicated than this, you probably want a typedef, and that is made exactly the same way as a variable, but with the <code>typedef</code> keyword before it.</p>
<p>So, <code>int (^block_variable)(int, int)</code> becomes:</p>
<pre><code>typedef int (^block_t)(int, int)
</code></pre>
<p>And then your method can be declared as:</p>
<pre><code>-(void)doBlock:(block_t)block_param
</code></pre>
<p>So, block syntax might make a little sense, as long as you remember:</p>
<ol>
<li>It's kind of like C pointers to functions</li>
<li>So, replace the name with the pointer operator</li>
<li>Oh yeah, and it needs to be in parens because of C's associativity rules</li>
<li>Except, use <code>^</code> instead of <code>*</code></li>
<li>And, if you need a name (for a variable or typedef), put it in the parens too (because C syntax)</li>
<li>But, if it's a method parameter, then just follow Objective-C style (extra parens and name outside)</li>
</ol>
<p>And if you don't get it on the first try, <a href="http://fuckingblocksyntax.com/">just look it the F up</a>.</p>Case Study: Contributing to Fastlane2018-03-23T19:41:48+00:00https://app-o-mat.com/post/how-to-contribute-to-fastlane<p>I came into work Monday to see our builds failing with a problem that was unconnected to anything we merged recently. Reading the logs, I could see that <em>fastlane's</em> <code>gym</code> was claiming that our scheme was not found in the workspace, but I knew that it was definitely there.</p>
<p><em><strong>Note for non-iOS devs:</strong> we use Xcode to manage workspace, project, and scheme files, which are just piles of undocumented XML. <a href="https://github.com/fastlane/fastlane"><strong>fastlane</strong></a> is an open-source project that makes it easy to script builds, tests, and a lot of other stuff. In order for fastlane to understand a workspace/project/scheme, the maintainers needed to reverse engineer the format and build parsers.</em></p>
<p><em>fastlane</em> is an incredibly fast moving project. Since they have to track (and reverse engineer) undocumented Apple things like project file formats and the iTunesConnect API, it's important to adopt their latest version pretty aggressively. So our build machine's package manager is set to download the latest release, which keeps us up to date, but also exposes us to bugs.</p>
<p>I saw that <em>fastlane</em> had released a new version that day, so I tried reverting to the one right before. That did "fix" the issue, but pinning <em>fastlane</em> is not a good option. I did it temporarily to get builds, but I needed a plan to get the problem fixed.</p>
<p>I've written that <a href="https://app-o-mat.com/post/3-web-techs-for-ios-devs">ruby is important for iOS developers to know</a>. My reasoning was that it was used for a lot of significant iOS tooling and if you rely on open-source projects, you need to be ready to fix your own problems.</p>
<p>Now, I don't know a lot of ruby. I probably couldn't make a real thing from scratch with it. But I do know enough to debug and fix small bugs.</p>
<p>Here was my process:</p>
<p><em>You'll see that each step wasn't really that hard and you can use this is a guide the next time you run into an issue with an open-source tool you rely on.</em></p>
<h4>Step 1: Read the commits</h4>
<p>Since I knew that the issue was introduced in the latest version, there was a small set of commits to look over. One of them was to <a href="https://github.com/fastlane/fastlane/commit/2388fc833e9c0c1609781bce5efe25c65c398dec">swap out bespoke Xcode project file parsing code</a> for <a href="https://github.com/CocoaPods/Xcodeproj">Cocoapod's Xcodeproj project</a>. This makes sense, but this commit is a good candidate for introducing my problem, which was not getting a full list of schemes from the workspace.</p>
<h4>Step 2: Do a little debugging</h4>
<p>I really wanted to write an issue at this point, but I still did not have any idea of what was going on. Xcodeproj is a mature project and used in cocoapods, so it's not likely that this bug was for a common case. If you want your issue to be taken seriously, you should do as much as you can to narrow down the problem and describe it well. Open-source projects get tons of issues opened by people that don't do enough to make the issue easy to deal with--you can stick out by doing more (which will get your issue fixed faster).</p>
<p>The commit above showed this new code:</p>
<pre><code>def workspace
return nil unless workspace?
@workspace ||= Xcodeproj::Workspace.new_from_xcworkspace(path)
end
def schemes
@schemes ||= if workspace?
workspace.schemes.reject do |k, v|
v.include?("Pods/Pods.xcodeproj")
end.keys
else
Xcodeproj::Project.schemes(path)
end
end
</code></pre>
<p>So, if the scheme list is not complete, it really looks like the issue is with Xcodeproj. That hypothesis is easy to test, I wrote this simple script</p>
<pre><code>require 'xcodeproj'
project_path = './Trellis.xcworkspace/'
workspace = Xcodeproj::Workspace.new_from_xcworkspace(project_path)
workspace.load_schemes(project_path)
print workspace.schemes
</code></pre>
<p>And ran it in my project's root.</p>
<p>It had the same problem as <em>fastlane</em>, which was a good sign. I read <code>load_schemes</code> and saw that it looks for <code>*.xcscheme</code> files in project directories. I did a <code>find</code> and saw that I had <code>xcscheme</code> files under the workspace folder as well. <code>load_schemes</code> doesn't look in that folder, though, so that was the problem.</p>
<h4>Step 3: Write up an Issue</h4>
<p>At this point, I could describe exactly what was going wrong and recommend a course of action, so <a href="https://github.com/fastlane/fastlane/issues/12113">I wrote an issue</a>. I was still going to do more, but the point of this was to see if anyone else had a workaround or was experiencing the same thing. Many people search issues when they have a problem, so I made sure to express the core problem in the issue title so it would be easy to find.</p>
<p>A couple of other devs did say they had the same issue, so I tried to help them diagnose based on my findings.</p>
<h4>Step 4: Make a simple test case</h4>
<p>Since I knew exactly what was going on, I could easily create a workspace that reproduced the issue. I did that and attached it to the issue. I also created an issue on Xcodeproj and attached the workspace to that one as well.</p>
<h4>Step 5: Try to fix it</h4>
<p>The bug was really in Xcodeproj, but the fix there was not obvious to me. I decided to work-around the issue in <em>fastlane</em>. The fix is pretty simple--I wrote a function to read the workspace schemes:</p>
<pre><code>def workspace_contained_schemes
Dir[File.join(path, 'xcshareddata', 'xcschemes', '*.xcscheme')].map do |scheme|
File.basename(scheme, '.xcscheme')
end
end
</code></pre>
<p>And appended this list to the one created in <code>schemes</code>.</p>
<h4>Step 6: Read fastlane's CONTRIBUTING.md</h4>
<p>At this point, I was sure I was going to make a PR, so I read their <a href="https://github.com/fastlane/fastlane/blob/master/CONTRIBUTING.md">contribution guidelines</a>. I learned</p>
<ol>
<li>I'd have to get a CLA signed by my job</li>
<li>How to make my local fastlane used in my iOS project (for testing)</li>
<li>How to run the tests</li>
<li>Branch and commit naming guidelines</li>
</ol>
<h4>Step 7: Make a new spec test</h4>
<p>Luckily I had made a simple test case workspace, so I added that to <em>fastlane's</em> fixtures and added <a href="https://github.com/fastlane/fastlane/pull/12124/commits/cbf8386f2806356629bf0a4782822c0c67d41614#diff-0c89fc498218c5eac1e68c05852bc347">a simple spec-based test</a> to make sure the new code read the workspace schemes. I actually found a bug while doing this, so I fixed that (the code in Step 5 is the fixed version).</p>
<h4>Step 8: Make a PR to fastlane</h4>
<p>The contribution guideline has a template for the PR message, which is also pre-populated when you open the PR. I made sure to follow the format.</p>
<h4>Step 9: Start the CLA signing process with my job</h4>
<p>I had to wait here, because the CLA is only sent to you after you open the PR. I then had to go through the steps at my job for contributing to an open-source project. Luckily, we were already signatories to the CLA, so I just needed to get myself added to it.</p>
<h4>Step 10: Make a PR to Xcodeproj</h4>
<p>By this time, one of the maintainers on Xcodeproj answered my question on what to do about the issue, so I made the PR to load workspace schemes there too. Xcodeproj has a simpler process for contributing, but I did also add the simple workspace to their fixtures and specs.</p>
<h4>Step 11: Shepherd the PRs until they are merged</h4>
<p>Both of these projects have automatic tests and bots responding to PRs, so I just made sure they were satisfied. I got a suggestion from a maintainer on the <em>fastlane</em> PR, so I addressed that.</p>
<h4>See? Simple.</h4>
<p>It does seem like a lot of steps, but the only hard part was debugging (did I mention how much of a ruby newb I am?). <em>fastlane</em> has great contributor documentation that helps getting a local development environment set up quickly. Their spec tests and code-style checker (rubocop) helped me fix issues before committing.</p>A snapshot of the iOS and/xor Android Developer Market2018-02-04T15:31:17+00:00https://app-o-mat.com/post/ios-android-mobile-dev-market-snapshot<p>When I wrote about <a href="/post/should-ios-devs-learn-android">whether or not iOS developers needed to know Android to be successful</a>, I had an instinct that the answer was no, and I did a spot-check of job-boards to make sure I wasn’t way off. Here’s a more in-depth look with links so you can check to make sure it still holds at a later date (my numbers are as of February 2018).</p>
<p>None of the links below are location, job-level, or salary restricted. You should add those to tailor this data to your specific situation.</p>
<h2>StackOverflow Developer Jobs</h2>
<p>This is my favorite job site. I got my last job through it and I especially recommend it for remote jobs.</p>
<ul>
<li><a href="https://stackoverflow.com/jobs?q=%5bios%5d+-%5bandroid%5d&rs=1&sort=p">Jobs tagged iOS, but not Android</a>: 59</li>
<li><a href="https://stackoverflow.com/jobs?q=-%5bios%5d+%5bandroid%5d&rs=1&sort=p">Jobs tagged Android, but not iOS</a>: 61</li>
<li><a href="https://stackoverflow.com/jobs?q=%5bios%5d+%5bandroid%5d&rs=1&sort=p">Jobs tagged iOS and Android</a>: 42</li>
<li><a href="https://stackoverflow.com/jobs?sort=p&q=ios+android">Jobs that mention iOS and Android anywhere</a>: 363</li>
</ul>
<p>So, knowing both does give you access to more jobs, but I would say you have a better chance at the platform specific job (especially the more senior ones) if you spent your time strengthening your platform knowledge. My presumption is that your time is finite, and so you need to prioritize.</p>
<p>Also, note that of the 363 jobs that mention iOS and Android, only 42 were tagged as needing both, or about 12%. Keep that in mind for the next few job boards, which don't have tagging.</p>
<p>In either case, either or both seems like a reasonable option, but you don’t <em>need</em> to know both if you don’t want to.</p>
<h2>Indeed</h2>
<p>I have used Indeed for a more general look at the market — they scrape job sites and employer websites, so generally have more listings. </p>
<p>I limited my searches to the last 7 days, and unfortunately, Indeed doesn’t have a good enough search to limit to tech “tags”, so I used title as a proxy for how important something was.</p>
<ul>
<li><a href="https://www.indeed.com/jobs?as_and=&as_phr=&as_any=&as_not=android&as_ttl=ios&as_cmp=&jt=all&st=&salary=&l=&fromage=7&limit=10&sort=&psf=advsrch">Jobs with iOS in the title, no mention of Android</a>: 156</li>
<li><a href="https://www.indeed.com/jobs?as_and=&as_phr=&as_any=&as_not=ios&as_ttl=android&as_cmp=&jt=all&st=&salary=&fromage=7&limit=10&sort=&psf=advsrch">Jobs with Android in the title, no mention of iOS</a>: 211</li>
<li><a href="https://www.indeed.com/jobs?as_and=&as_phr=&as_any=&as_ttl=android+ios&as_cmp=&jt=all&st=&salary=&fromage=7&limit=10&sort=&psf=advsrch">Jobs that mention both iOS and Android in title</a>: 17 </li>
<li><a href="https://www.indeed.com/jobs?as_and=ios+android&as_phr=&as_any=&as_not=&as_ttl=mobile&as_cmp=&jt=all&st=&salary=&l=&fromage=7&limit=10&sort=&psf=advsrch">Jobs with Mobile in title that mention both iOS and Android anywhere</a>: 197</li>
</ul>
<p><a href="https://www.indeed.com/jobs?as_and=ios+android&as_phr=&as_any=&as_not=&as_cmp=&jt=all&st=&salary=&fromage=7&limit=10&sort=&psf=advsrch">If you don’t use “Mobile” in the title on the last one</a>, you get 1,403 jobs, but it was hard to tell if this over included a lot of jobs that weren’t development or were even more general than just mobile.</p>
<p>So, let’s say it’s somewhere in-between, or 800 jobs (168 if we use 12% from StackOverflow). That’s significantly more than either platform, but again, it’s not as if there aren’t jobs in the platform-specific categories. This does point to a benefit of knowing both, but doesn’t make me think you need to know both.</p>
<p>One thing to do with these searches, is narrow them down even further to your location, salary range, experience level and other requirements to make sure it still holds for you.</p>
<h2>Dice</h2>
<p>Dice is one of the bigger developer-specific job boards. Like Indeed it will have more listings, and we need to use title as a proxy for a tag.</p>
<ul>
<li><a href="https://www.dice.com/jobs/advancedResult.html?for_one=&for_all=&for_exact=&for_none=android&for_jt=ios&for_com=&for_loc=&sort=date&radius=30">Jobs with iOS in the title, no mention of Android</a>: 320</li>
<li><a href="https://www.dice.com/jobs?q=-ios+title%3A%28android%29&l=">Jobs with Android in the title, no mention of iOS</a>: 327</li>
<li><a href="https://www.dice.com/jobs?q=title%3A%28ios+android%29&l=">Jobs that mention both iOS and Android in title</a>: 10</li>
<li><a href="https://www.dice.com/jobs?q=ios+android+title%3A%28mobile%29&l=">Jobs with Mobile in title that mention both iOS and Android anywhere</a>: 405</li>
<li><a href="https://www.dice.com/jobs?q=ios+android&l=">Jobs that mention iOS and Android anywhere</a>: 2,797</li>
</ul>
<p>If I average the last two, it’s about 1,600 jobs (or 336 if they were tagged at the same ratio as StackOverflow), so again, significantly more. I trust these jobs to be mostly in development (or related jobs). This is even more evidence that having both is an advantage, but I still think it’s not a requirement.</p>
<p>Based on this data, I’d say there are more jobs that require both, but still enough of a market to specialize if you want to. </p>
<p>Remember that even a little experience in your non-dominant platform would open up more of those cross-platform jobs, as I am sure the minimum requirement is a huge range. Meaning, if you were a very advanced iOS developer, and had 6 months of Android, you could reasonably apply to many jobs that require both.</p>Do iOS Developers Need to Know Android?2018-02-03T18:59:17+00:00https://app-o-mat.com/post/should-ios-devs-learn-android<p>No.</p>
<p>That answer might be unsatisfying, but I think there’s a more important question, which I’ll get to in a moment.</p>
<p>Underlying questions like “Do I need to know X” is the unwritten clause: “to get a job” or “to be successful” and the feeling of not wanting to learn X if you don’t have to.</p>
<p>I have that feeling — I know very little about Android. It’s not that I don’t want to venture out of iOS (iOS is probably my third or fourth full-time platform switch) — it’s that I know that there is only a finite amount of time I can spend on learning other things. For my goals, strengthening my back-end skills is a better use of time (<a href="/post/3-web-techs-for-ios-devs">and that would be my general recommendation</a>).</p>
<p>To me the question is: </p>
<h2>When should iOS developers learn Android?</h2>
<p>There are circumstances when full-time iOS developers should spend some time learing Android. Most of these are from my personal experience (which I have already said does not include much Android) — so, obviously, I might not know what I’m talking about.</p>
<h3>1. If your title is Mobile X or you aspire for it to be (most likely management)</h3>
<p>My first brush with Android was when the team I was leading was assigned to build mobile versions of our image processing tools. I already had four or five years of iOS experience, so I was very comfortable there, but I did spend some time getting to know the parts of Android we were going to use. In this case, since we were making libraries, and not apps, that exposure was pretty limited.</p>
<p>But if you aspire to be a “mobile” lead, manager, product manager, or leadership in a mobile-first company, you can’t afford to be a blank on Android.</p>
<h3>2. If your iOS work is via any cross-platform framework (e.g.: Ionic, Cordova, Xamarin, etc)</h3>
<p>My next time with Android was when I was an independent contractor and I started to get work adding native iOS pieces to Cordova projects. Since I generally became an expert in Cordova, when I looked for other work, they typically needed the Android parts done as well.</p>
<p>Again, this is not like Android app development — it’s Cordova plugin development, but I did need to know how to do it for both platforms. (BTW, this site started with <a href="/screencasts/">my Cordova tutorial screencasts</a>).</p>
<h3>3. If you think you might want to switch to Android</h3>
<p>This is obvious, so I’ll just list it here for completeness.</p>
<h3>4. If you work on mobile team with native Android devs</h3>
<p>This is the case for me now. It is really convenient for me to be able to read the Android team’s code. I do this when I have to implement something in iOS that is already in the Android version.</p>
<p>I already know Java which is sufficient because most of the time I’m interested in network, algorithmic, and database code (not UI, which will be way different).</p>
<h2>Is that it?</h2>
<p>Of course not. Hey, you might have made a game on the side and now it’s climbing the iOS charts — porting to Android seems like a good use of time (even if you farm it out, it’s good to know something about the work required). And of course, if you just <em>want</em> to learn Android development, then go ahead.</p>
<p>Do you have different thoughts about this? <a href="/contact/">Get in touch</a>.</p>
<p><strong>Added later:</strong> Read the follow-up: <a href="/post/ios-android-mobile-dev-market-snapshot">A snapshot of the iOS and/xor Android Developer Market</a></p>Why Why Why Why Your iOS App Might Act Weird around New Year's2017-12-09T18:40:58+00:00https://app-o-mat.com/post/why-why-why-why<p>Consider this snippet from a playground</p>
<pre><code>let df = DateFormatter()
df.dateFormat = "YYYY-MM-dd"
df.string(from: Date(year: 2017, month: 12, day:30)!)
</code></pre>
<p>The result is <code>"2017-12-30"</code> as you might expect.</p>
<p>But, try the next day:</p>
<p><img alt="YYYY" src="//media.app-o-mat.com/site-images/YYYY.png" title="YYYY" /></p>
<p>The reason is because <code>YYYY</code> is not what you think it is. The correct way to format the year part of a date is with <code>yyyy</code>. There’s a good <a href="https://stackoverflow.com/questions/12423179/nsdateformatter-show-wrong-year">answer on StackOverflow that explains why</a>, but the short version is that <code>YYYY</code> is part of a formatting system based on week of the year, which always starts on a Sunday (EDIT: in the US, that is. Other locales’ weeks start on different days, so the exact dates that will be wrong vary by locale — thanks to dc6k and others on <a href="https://reddit.com/r/iOSProgramming/comments/7iopyx/why_why_why_why_your_ios_app_might_act_weird/">r/iOSProgramming</a> for the correction)</p>
<p>December 31st, 2017 is the first day of the first week of <strong>2018</strong>. If you are using the week-of-year formatting system, then <code>YYYY</code> is what you do to get the year part out. On other years, you might find that the first week of January has a <code>YYYY</code> of the previous calendar year.</p>
<p>So, stop what you’re doing right now and search your codebase for <code>YYYY</code> and fix it if you find any. You have a week or so to submit before Apple closes the App Store for the holidays.</p>
<p>Don’t feel bad if you find it, though. In 2013, <a href="https://arstechnica.com/gadgets/2013/01/ask-ars-why-will-apples-do-not-disturb-bug-fix-itself-next-week/">Apple got caught with the YYYY bug</a> and in 2014, <a href="https://blog.antoine-augusti.fr/2014/12/twitter-api-app-down-5-hours-calendars/">Twitter went down for five hours because of it</a>.</p>
<p>Oh yeah, this isn’t just an iOS issue. The format string that <code>DateFormat</code> uses is part of a standard that a lot of languages/frameworks use, so check your code no matter what it’s written in (and check your docs, of course). iOS devs do have a limited time window though because of review times and the App Store holiday.</p>Getting the Most out of WTF Auto Layout2017-10-02T12:17:02+00:00https://app-o-mat.com/post/make-wtf-auto-layout-even-better<p>The next time you see the dreaded:</p>
<blockquote>
<p>Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want</p>
</blockquote>
<p>take a look at <a href="https://www.wtfautolayout.com/">WTF Auto Layout</a>.</p>
<p>It parses the list of constraints that Xcode dumps into the console and gives you a visual representation of what your ambiguous constraints are trying to do.</p>
<p>But WTF Auto Layout can only label the views with however Xcode decided to label them, which is just their typename by default, so you might end up with something like this:</p>
<p><img alt="" src="//media.app-o-mat.com/site-images/wtf-al-visual_pW5HpTZ.png" /></p>
<p>In a simple view, this might be enough to help you, but you probably don’t need WTF Auto Layout for your simple problems. With just typenames, this isn’t going to help much.</p>
<p>Luckily, Xcode will use other cues from your view to pick up names. Here are other places Xcode will try to get labels for this error message:</p>
<ol>
<li>The text in views that show text (like <code>UILabel</code> and <code>UIButton</code>).</li>
<li>The names of IBOutlet properties</li>
<li>The <strong>Xcode Specific Label</strong> in the Document section of the Identity Inspector in Interface Builder.</li>
<li>The constraint’s <code>identifer</code> property.</li>
</ol>
<p>So, if you get an error that you are having a hard time understanding, start filling in constraint identifiers and Xcode labels to help WTF Auto Layout give you something more you can work with.</p>How to Learn what Auto Layout Errors Mean2017-09-23T21:10:49+00:00https://app-o-mat.com/post/infinite-autolayout-tutorials<p>You’ve done the Stanford iOS course and all of the Wenderlich Auto Layout tutorials, but your app is still dumping</p>
<blockquote>
<p><strong>Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want</strong></p>
</blockquote>
<p>to the console every time you make a new screen.</p>
<p>You ask on StackOverflow, but the question gets closed because there’s no good way to paste your Storyboard into a box that wants Markdown. And screenshots are even worse.</p>
<p><strong>It’s so frustrating</strong>—why can’t Xcode show a better error?!?</p>
<h3>Xcode doesn’t really know what’s going on</h3>
<p>Auto Layout errors are hard to understand because Xcode doesn’t know how to explain what’s wrong. </p>
<p>Auto Layout is a complex algorithm. All it knows is that it can’t figure out the position of a view, but it might not know why or how to tell you which view is having the problem. And when it finds a conflict in the constraints, it doesn’t really know which one is the extra one, so it removes one randomly.</p>
<p>But, over time, by working on a lot of constraint-based layouts, and running into (and then solving) problems, these errors actually start to make sense.</p>
<p>So, all you really need is practice.</p>
<p>But even if you work on apps full-time, you’ll spend very little time on Auto Layout, so <strong>it’s hard to get enough exposure.</strong></p>
<h3>You can jump start this process</h3>
<p>One of my tips to programmers learning any new technology for the first time is to <strong>break working things on purpose</strong>. </p>
<p>Then, go look at the broken thing and see how it behaves. Generally, when we make broken things, we don’t really know how it’s broken, but you totally know what’s wrong this time because you know how you broke it.</p>
<p>So, now you can fix it.</p>
<p>To help with this process, I wrote <a href="https://github.com/loufranco/EventOMat">EventOMat</a>, a simple app to support a talk I gave at NerdSummit earlier this year. It implements the conference’s agenda (and can be used as a template for any conference).</p>
<p>But if you go to the repository, you’ll see that there are a bunch of “exercise” branches (e.g. <a href="https://github.com/loufranco/EventOMat/tree/exercises/01-set-date">here’s the first exercise</a>). Each exercise branch is the full app with a few lines of code (or some part of the Storyboard) removed. </p>
<p>The <code>README</code> in each branch has hints about how to fix it. If you get stuck, you can just look at the last few commits in the branch that set up the exercise.</p>
<h3>Make a missing constraint tutorial</h3>
<p>You can use this app to make as many Auto Layout practice exercises as you want.</p>
<p>Here’s how we make a new one from the master branch.</p>
<h4><strong>Step 1:</strong> Choose a constraint in the storyboard</h4>
<p><img alt="" src="//media.app-o-mat.com/site-images/01-removing-constraint.png" title="About to remove a constraint" /></p>
<h4><strong>Step 2:</strong> Delete it</h4>
<p><img alt="" src="//media.app-o-mat.com/site-images/02-after-constraint-remove.png" title="Remove the constraint" /></p>
<h4><strong>Step 3:</strong> Read the error and relate it to what you just did</h4>
<p><img alt="" src="//media.app-o-mat.com/site-images/03-constraint-remove-error.png" title="Read the error" /></p>
<p>This one is simple—it says that the <strong>Trailing constraint is missing</strong> for <strong>Label</strong> and highlights it. Your job is to put in a trailing constraint.</p>
<h3>Don’t let Xcode make the constraint</h3>
<p>If you click the yellow warning icon, Xcode will offer to make the constraint for you. DON’T DO THIS.</p>
<p>The problem is that Xcode doesn’t know what you want the view to look like, so it will make a constraint that preserves the sizes and positions that you currently see.</p>
<p>But we want the view to stretch the whole width, so set the trailing anchor to be equal to its superview’s trailing anchor.</p>
<h3>Make as many as you need</h3>
<p>I pushed the broken branch as <a href="https://github.com/loufranco/EventOMat/tree/exercises/06-missing-constraint">Exercise 6 in EventOMat</a> if you want to try it out.</p>
<p>But don’t stop there. You can use this app (or any working one) as a starting point to learn more about Auto Layout. Just pick some constraint and remove it. Then relate that to the error you get and fix it.</p>
<p>After you have done that a while, start adding in new constraints. This will probably over-specify the constraint system and cause different errors (sometimes just in different device sizes).</p>
<p>I have a lot more to say on this topic, so subscribe below to make sure you don’t miss more ways to learn and practice Auto Layout.</p>