<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[The Traveled iOS Developer’s Guide - Medium]]></title>
        <description><![CDATA[Cocoa Touch, unwrapped and analyzed by @JordanMorgan10. Updated biweekly. - Medium]]></description>
        <link>https://medium.com/the-traveled-ios-developers-guide?source=rss----79a4c0617ed4---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>The Traveled iOS Developer’s Guide - Medium</title>
            <link>https://medium.com/the-traveled-ios-developers-guide?source=rss----79a4c0617ed4---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 22 May 2026 13:39:15 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/the-traveled-ios-developers-guide" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Introducing Swiftjective-C]]></title>
            <link>https://medium.com/the-traveled-ios-developers-guide/introducing-swiftjective-c-90dbbd30b416?source=rss----79a4c0617ed4---4</link>
            <guid isPermaLink="false">https://medium.com/p/90dbbd30b416</guid>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Jordan Morgan]]></dc:creator>
            <pubDate>Sun, 28 Oct 2018 21:52:48 GMT</pubDate>
            <atom:updated>2018-10-28T21:52:48.113Z</atom:updated>
            <content:encoded><![CDATA[<h4>A new home for my writing.</h4><p>I’ve been thankful to find a new audience here on Medium, but for some time I’ve yearned to have a little place on the internet to call home. By the same token, though iOS is my career and passion — I have missed dipping into some front-end development.</p><p>To that end, I’d love to introduce you to the new home of all my articles going forward:</p><p><a href="https://www.swiftjectivec.com/index.html">Swiftjective-C</a></p><p>Swiftjective-C!</p><p>I created it using Jekyll, and the whole entire thing is open source as well. Thanks for reading all these years, and I hope you’ll follow along with me at my new home.</p><p>Until next time ✌️.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=90dbbd30b416" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-traveled-ios-developers-guide/introducing-swiftjective-c-90dbbd30b416">Introducing Swiftjective-C</a> was originally published in <a href="https://medium.com/the-traveled-ios-developers-guide">The Traveled iOS Developer’s Guide</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[UIGraphicsImageRenderer]]></title>
            <link>https://medium.com/the-traveled-ios-developers-guide/uigraphicsimagerenderer-fe40edc3a464?source=rss----79a4c0617ed4---4</link>
            <guid isPermaLink="false">https://medium.com/p/fe40edc3a464</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[developer]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Jordan Morgan]]></dc:creator>
            <pubDate>Wed, 01 Aug 2018 20:23:12 GMT</pubDate>
            <atom:updated>2018-12-19T22:41:15.209Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*R3n7VYv1Ces7sD9jgy3bHw.jpeg" /><figcaption>Pass those mocks for the stock photo, photo-op!</figcaption></figure><h4>Modern Drawing on iOS</h4><blockquote>A quick note — all of my future posts will be published on my <a href="https://www.swiftjectivec.com/index.html">dedicated website</a> and this publication is no longer being updated. Thanks for reading!</blockquote><p>The history of photography is rife with interesting stories of how the medium developed. Among them, digital photography is one of the more exciting bits of its history. It’s still quite a nascent craft, with its history tracing back to as recently as 1957 when the fine folks at the National Institute of Standards and Technology slapped a photo into computer memory.</p><p>The translation from the analog to the digital was an inflection point. We’ve experienced a similar shift on iOS starting with iOS 10, though many engineers have yet to discover or adopt the latest innovation for drawing images — UIGraphicsImageRenderer.</p><h4>Setting the (CG)Context</h4><p>Core Graphics, based on the Quartz drawing engine, has provided iOS developers with lightweight 2D rendering capabilities since iOS 2. Its utility knows almost no bounds, as image masking, PDF document creation, parsing, and other similar functions are baked right in making it a no nonsense choice for any sort of drawing task.</p><p>For that and many other reasons, if one hits the Googles on how to create an image from something on screen they’ll likely end up with something like this:</p><pre>let drawSize = CGSize(width: 20, height: 20)</pre><pre>UIGraphicsBeginImageContext(drawSize)<br>let ctx = UIGraphicsGetCurrentContext()!</pre><pre>ctx.setFillColor(UIColor.red.cgColor)<br>ctx.fill(CGRect(x: 0, y: 0, width: drawSize.width, height: drawSize.height))</pre><pre>let img = UIGraphicsGetImageFromCurrentImageContext()</pre><p>And it works, so we move on. Though, there are several valid reasons to pump the breaks:</p><ul><li>UIGraphicsBegin/EndImageContext are sRGB only (sorry p3 color gamut).</li><li>It was before the age of blocks, which are common throughout Foundation, UIKit and virtually every framework on iOS.</li><li>Extensibility is possible, though sometimes a non trivial task.</li></ul><p>Given its age, it’s not a shocker to say Core Graphics provides an API that’s less than ideal too many of today’s standards. Though Swift’s syntactical sugar prowess has softened the call sites to Core Graphics code over many projects, it still is what it is — a C based API built for simpler times.</p><p>In contrast, UIGraphicsImageRenderer is built for tomorrow in mind:</p><ul><li>It’s automagically fully color managed. For example, on the beautiful 9.7 inch iPad pro you’ll get a wide color context.</li><li>It’s a first class object.</li><li>It manages its context lifetime, unlocking some memory optimizations on the house from Cupertino &amp; Friends©.</li><li>The former implicitly means that it caches its context, meaning reuse is an efficient operation as opposed to using new renderers.</li></ul><h4>Gaining More (CG)Context</h4><p>Initializing and keeping a reference to a renderer is a solid start:</p><pre>let renderer = UIGraphicsImageRenderer(size: CGSize(width: 20, height: 20))</pre><p>From there, the relevant parallel from the old way of doing things to the preferred, Apple approved way would be image renderer’s closure based functions for creating an image:</p><pre>func image(actions: (UIGraphicsImageRendererContext) -&gt; Void) -&gt; UIImage</pre><p>To compare apples to image renderers, one could create the same image as mentioned above from the legacy Core Graphics method by doing this:</p><pre>let img = renderer.image { (ctx) in<br>    let size = renderer.format.bounds.size<br>    UIColor.red.setFill()<br>    ctx.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))<br>}</pre><p>The hard work of what’s happening here has always been abstracted away by Core Graphics since day one, but now it’s more honed in to the point where we simply spit out some drawing instructions within a block.</p><p>The renderer also exposes convenient access to getting a hold of NSData of resulting images as well:</p><pre>let actions:(UIGraphicsImageRendererContext) -&gt; Void = { (ctx) in<br>    let size = ctx.format.bounds.size<br>    UIColor.blue.setFill()<br>    ctx.fill(CGRect(x: 1, y: 1, width: size.width - 1, height: size.height - 1))<br>}</pre><pre>let imageJPEGData = renderer.jpegData(withCompressionQuality: 1, actions: actions)</pre><pre>let imagePNGData = renderer.pngData(actions: actions)</pre><p>In each code sample, the typealiased DrawingActions closure returns to us an instance of UIGraphicsImageRendererContext. Using it we gain access high-level drawing functions. Though Apple clearly states “higher level” drawing functions, don’t think of it as a crutch. There is support for most drawing tasks, such as utilizing blend modes by leveraging CGBlendValue:</p><pre>let image = renderer.image { (ctx) in<br>    UIColor.blue.setFill()<br>    ctx.fill(CGRect(x: 1, y: 1, width: 140, height: 140))</pre><pre>    UIColor.yellow.setFill()<br>    ctx.fill(CGRect(x: 60, y: 60, width: 140, height: 140), blendMode: .luminosity)<br>}</pre><p>That said, you may be left missing the drawing functionality you might’ve thought left behind from the traditional context.</p><p>For example, filling in an ellipses still requires a R.O.C.G.C. (regular old Core Graphics Context, obviously). To fill out the drawing functionality (pun somewhat intended), an image renderer context has one available.</p><p>Take note of the last two lines, where the cgContext allows us to fill out the circle:</p><pre>let img = renderer.image { (ctx) in<br>    let size = ctx.format.bounds.size<br>    <br>    UIColor.darkGray.setStroke()<br>    ctx.stroke(renderer.format.bounds)</pre><pre>    UIColor.blue.setFill()<br>    ctx.fill(CGRect(x: 1, y: 1, width: size.width - 1, height: size.height - 1))<br>    <br>     UIColor.yellow.setFill()<br>     ctx.cgContext.fillEllipse(in: CGRect(x: 51, y: 51, width: size.width/2, height: size.width/2))<br>     ctx.cgContext.rotate(by: 100)<br>}</pre><h4>Giving a Renderer More (CG)Context</h4><p>I really need to stop with the (CG)Context bit, but I feel too invested at this point so please just excuse me 🤠.</p><p>You have noticed that a graphics renderer will also accept a UIGraphicsImageRendererFormatobject into two of its four available initializers:</p><pre>public init(size: CGSize, format: UIGraphicsImageRendererFormat)<br>public init(bounds: CGRect, format: UIGraphicsImageRendererFormat)</pre><p>This rendering format has a few options to aid in further specifying the intent of your resulting drawing operations. It also has a useful bounds property we’ve been using in the previous code samples that’s derived from its associated graphics context. Using this formatter one can tweak opaque or scale preferences, among other things.</p><p>For example, CALayer and its A8 backing store format was introduced in iOS 12 and provides developers with free memory optimizations. If you’re certain, for example, that you’re drawing wide color content <em>using</em> sRGB colors, you can have the renderer optimize for that since the backing store would otherwise be larger to accommodate a larger color range rather than just 0 to 1:</p><pre>// iOS 10/11<br>let format = UIGraphicsImageRendererFormat()<br>format.prefersExtendedRange = false</pre><pre>// iOS 12<br>let format = UIGraphicsImageRendererFormat()<br>format.preferredRange = .standard // Turn off iOS 12 optimization</pre><p>Many of these decisions will likely be tied to the current trait collection, so it stands to reason that the renderer format can also be fetched on a per trait collection basis as well.</p><p>No need to mince in my own words here, Apple’s documentation explains this very well:</p><pre>// Returns a format optimized for the specified trait collection, taking into account properties such as displayScale and displayGamut.</pre><pre>// Traits that are not specified will be ignored, with their corresponding format properties defaulting to the values in preferredFormat.<br>public convenience init(for traitCollection: UITraitCollection)</pre><p>No worries if you opt to forgo any of this, as UIKit provides sensible default values for you should you not provide explicit ones. As such, if you do nothing, UIKit gives you the resulting format from its factory method, defaultFormat — which provides a format configured for the highest fidelity possible as supported by the device it’s executed on.</p><p>Take care to make this choice upfront, however. If you want to configure things, do it at your renderer’s initialization point as the formatter itself holistically represents immutable configurations that it will always use during drawing operations.</p><p>All of this hopefully should remind you how extensible and flexible an image renderer can be. For example, hanging a quick extension off of any view to create a circle avatar would be painless and performant (as performant as using cornerRadius can really be, that is) since one could reuse the same renderer and its context:</p><pre>private var rendererKey: UInt8 = 0</pre><pre>extension UIView {</pre><pre>    var renderer: UIGraphicsImageRenderer! {<br>         get {<br>             guard let rendererInstance = objc_getAssociatedObject(self, &amp;rendererKey) as? UIGraphicsImageRenderer else {<br>                self.renderer = UIGraphicsImageRenderer(bounds: bounds)<br>                return self.renderer<br>             }</pre><pre>             return rendererInstance</pre><pre>        }<br>        set(newValue) {<br>            objc_setAssociatedObject(self, &amp;rendererKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)<br>        }<br>    }</pre><pre>    func circleImageView() -&gt; UIImageView {<br>        let img:UIImage = renderer.image { ctx in<br>           layer.render(in: ctx.cgContext)<br>        }</pre><pre>        let imageView:UIImageView = UIImageView(image: img)<br>        imageView.frame = renderer.format.bounds<br>        imageView.clipsToBounds = true<br>        imageView.layer.cornerRadius =(renderer.format.bounds.width/2).rounded()<br>        return imageView<br>    }<br>}</pre><pre>// Generate a circle image and image view of any view instance<br>let anImageView = myExistingView.circleImageView()</pre><h4>PDFs FTW</h4><p>A quick sidebar to mention that the PDF variant of the abstract UIGraphicsRenderer class is very similar to its image rendering sibling. In fact, their method declarations are almost interchangeable, save UIImage vs Data:</p><pre>let renderer = UIGraphicsPDFRenderer(bounds: view.bounds)<br>let pdf = renderer.pdfData { (ctx) in<br>    ctx.beginPage()</pre><pre>    let header = &quot;Welcome to TTIDG!&quot; as NSString<br>    let attributes = [<br>        NSAttributedStringKey.font : UIFont.preferredFont(forTextStyle: .body),<br>        NSAttributedStringKey.foregroundColor : UIColor.blue<br>    ]</pre><pre>    header.draw(in: CGRect(x: 0, y: 0, width: ctx.pdfContextBounds.width, height: ctx.pdfContextBounds.height), withAttributes: attributes)<br>}</pre><h4>Wrapping Up</h4><p>Replacing the code that kinda just works with the code that’s more recent and supports more relevant formats is typically not high on the proverbial list.</p><p>Maybe it should be, as is the case with UIGraphicsImageRenderer. You likely won’t have to twist many arms to persuade iOS engineers to make the switch, “No ✋ — I don’t want block based, automatically color managed, extensible drawing code that already manages its context lifetime — that’s awful” said…..nobody?</p><p>Until next time, may your drawing exploits with UIGraphicsImageRenderer be many and productive 📸.</p><p><a href="https://www.twitter.com/jordanmorgan10">Jordan Morgan (@JordanMorgan10) | Twitter</a></p><pre>If you enjoyed this week&#39;s post, please feel free to go ahead and NSRecommend(this, where: below);</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fe40edc3a464" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-traveled-ios-developers-guide/uigraphicsimagerenderer-fe40edc3a464">UIGraphicsImageRenderer</a> was originally published in <a href="https://medium.com/the-traveled-ios-developers-guide">The Traveled iOS Developer’s Guide</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[iOS 12: Notable UIKit Additions]]></title>
            <link>https://medium.com/the-traveled-ios-developers-guide/ios-12-notable-uikit-additions-b50beb0e3729?source=rss----79a4c0617ed4---4</link>
            <guid isPermaLink="false">https://medium.com/p/b50beb0e3729</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[apple]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Jordan Morgan]]></dc:creator>
            <pubDate>Fri, 08 Jun 2018 05:46:44 GMT</pubDate>
            <atom:updated>2018-12-19T22:41:52.255Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*y5nsXq1oeXf8RtGdM5eCaQ.jpeg" /><figcaption>An ode to headphone jacks refusing to go out to pasture on MacBook Pros 🎧.</figcaption></figure><h4>Let’s UIView What’s New #PunGameStrong</h4><blockquote>A quick note — all of my future posts will be published on my <a href="https://www.swiftjectivec.com/index.html">dedicated website</a> and this publication is no longer being updated. Thanks for reading!</blockquote><p>And here we are. We’ve finally got a good look at iOS 12 and all it has on offer. Though some chose to view it as a tame maintenance release, tagging it as such is a disservice and there was plenty to digest during the WWDC keynote.</p><p>Each year, I dive in on the latest version of iOS and try to bring up some of the new APIs that our favorite framework, UIKit, has brought to the table. In no particular order, let’s dig in on some of the enhancements that caught my eye.</p><h4>UITextInputTraits</h4><p>Apple continues its push towards keeping its user‘s data private and secure, so it’s no surprise to see Cupertino &amp; Friends© extend the password autofill APIs.</p><p>New this year is the ability to suggest a new password for your users, <em>and</em> supply your password parameters dictated by business requirements to iOS when suggesting such a password. This is done via the UITextInputPasswordRules class:</p><pre>let createNewPasswordTextField = UITextField()</pre><pre>let newPasswordReqs = UITextInputPasswordRules(descriptor: &quot;required: lower; required: digit; max-consecutive: 3; minlength: 12;”)</pre><pre>createNewPasswordTextField.passwordRules = newPasswordReqs</pre><pre>// Now, when iOS suggests a new password - these rules will be used to generate it</pre><p>The pertinent information here is the descriptor parameter, which is a plain string that follows a certain syntax, à la the visual format language:</p><pre>&quot;key: value;&quot;</pre><p>Think of it a dictionary entry that always is followed by semicolon. It’s quite close to CSS declarations. With it, you can specify the following items:</p><ul><li>required : Self explanatory</li><li>allowed : Allow a subset of allowed characters</li><li>max-consecutive : Restrict the number of successive characters</li></ul><p>And character classes to match against those rules:</p><ul><li>upper : A-Z</li><li>lower : a-z</li><li>special: -~!@#$%^&amp;*_+=`|(){}[:;”’&lt;&gt;,.? ] and space</li><li>ascii-printable : All ACII printable</li><li>unicode : All unicode</li></ul><p>To further things a little, suppose you only wanted to allow the letters “j,o,r,d,a,n” because you want the strongest password that I’ll never, ever most definitely guess, then you could do this:</p><pre>UITextInputPasswordRules(descriptor: &quot;required: [j,o,r,d,a,n]; max-consecutive: 2; minlength: 12;”)</pre><p>Be aware that the framework has some validation against your supplied validation, resulting in some form of validationception.</p><p>Your parameters have to <em>at least</em> use two instances of the ASCII uppercase letters, digits and ASDII lowercase letters classes. Other than that, it also must be longer than 12 characters.</p><p>If you don’t meet this criteria, do you get some sort of runtime error or exception? Nope — the user agent just throws out your insecure, primitive suggestion and uses the default. Which is probably a good thing.</p><p>As a bonus, you can do the same thing in HTML by using the passwordrules attribute in your input element.</p><h4>One Time TFA Codes</h4><p>In one of my favorite “It just works” APIs that Apple supplies to developers, it’s hard to argue that there’s something more trivial to implement in iOS development that simultaneously brings real value to users than setting a text content type.</p><p>The powerful heuristics of iOS sucks in passwords and phone numbers, can suggest a relevant address and more. And now, that more is TFA codes, accomplished by doing nothing more than choosing oneTimeCode:</p><pre>aTFAtextField.textContentType = .oneTimeCode</pre><p>This also joins the new value, newPassword, which would enable the password creation prompts touched on above. The usual restrictions (if you can even call them that) is that the element accepting the password must be a text field, text view or a view that adopts the UITextInput protocol.</p><p>Of note, tvOS apps are also granted the same affordances when using the control center keyboard, the continuity keyboard or even Cupertino’s Remote App. And let’s face it, nobody wants to type on that platform so any shortcuts we can provide just promotes engagement that much more.</p><p>Text content type is powerful, but also the definition of lightweight, simple and WYSIWYG. Sometimes what you aren’t is just as important as what you are. That’s also true with framework design.</p><h4>Graphics Rendering</h4><p>As we’ll briefly discuss later on, iOS 12 has automatic backing store support for views. The depth of their content drives this. So, for example, if you are rendering a grey scale image on the screen iOS will employ an 8 bit per pixel backing store instead of the usual 64 bit per pixel backing store a portrait image would incur.</p><p>The cost savings is significant, in the <a href="https://developer.apple.com/videos/play/wwdc2018/202/">What’s New in Cocoa Touch</a> session, Apple engineer Josh Shaffer notes that the previous example goes from 2.2 megabytes of real estate down to <em>275 kilobytes</em>.</p><p>As aforementioned, views get this out of the box. If you draw into offscreen bitmaps using UIGraphicsImageRenderer, though, iOS won’t be able to predict the developer’s intentions with the resulting image. As such, a configurable buffer backing store style has been introduced so one can take part in the memory savings:</p><pre>let rendererFormat = UIGraphicsImageRendererFormat.default()<br>rendererFormat.preferredRange = .extended // For an extended range image</pre><pre>let renderer = UIGraphicsImageRenderer(size: CGSize(width: 100, height: 100), format: rendererFormat)</pre><p>Above, we indicated our intention to utilize an extended range image. Though, we can also indicate that its unspecified, automatic or standard.</p><h4>The Small Quick Win</h4><p>Detecting user interface orientations is traditionally frowned upon via Apple’s official stance. And though trait collections offer us most of what we need, it’s still refreshing to see Apple come full circle on all the edge cases with two new additions here:</p><pre>let device = UIDevice.current<br>let isFlat = device.orientation.isFlat<br>let isValid = device.orientation.isValidInterfaceOrientation</pre><h4>Darkness for Days</h4><p>Also, we have dark mode on iOS, finally! Mojave doesn’t get all the fun!</p><p>Err…shoot, no wait — we just have API support for it. But it doesn’t officially exist. But it also kinda does too, because the code is there. It’s shipped with Xcode.</p><p>I don’t know. I’m just telling you that trait collections now know about it:</p><pre>let darkTraitCollection = UITraitCollection(userInterfaceStyle: .dark)</pre><p>…there’s obviously enumerations for it:</p><pre>@available(iOS 12.0, *) public enum UIUserInterfaceStyle : Int {<br>    case unspecified<br>    case light<br>    case dark<br>}</pre><p>…but they only apply to CarPlay on iOS 12 beta 1.</p><p>So there you go 🤷🏻‍♂️.</p><h4>Notifications</h4><p>Technically not part of UIKit, but I did have to highlight one welcome change aside from the new grouping capabilities. Look, dealing with notifications is often a pain from a developer perspective. While not a forgone conclusion, the more notification offerings we have to support, generally the issues that could arise grow exponentially.</p><p>You have the system notification view to toggle app permissions within iOS’ settings, possibly your own user interface to allow for granular choices, APNS to go through and oh, let’s not forget the network to contend with too.</p><p>So, the fact that you can deep link directly into your app’s notification settings from an incoming one is not a small improvement (via providesAppNotificationSettings), but a very welcome change as developers continue their journey towards simplifying notification issues for them, the end user and customer support.</p><p>🕺!</p><h4>… And The Free Ones 🙌</h4><p><a href="https://twitter.com/_inside/status/1003831980025372673">iOS 12 is fast</a>. A lot of the improvements we’ll enjoy come from deep within the framework itself. Here, I’ve chosen to highlight API changes you’ll need to put some time into to reap benefits.</p><p>But that’s the thing — our apps will feel a bit smoother, faster and coherent without us having done anything at all.</p><p>The reasons why range from smarter cell prefetching via the API scheduling things serially, smarter CPU diversification, more intelligent backing stores for UIView and Auto Layout (quite impressively) hitting O(n) instead of O(n²) for multiple common layout scenarios, to name a few.</p><h4>Wrapping Up</h4><p>Personally, I came away more impressed than I thought I would be with iOS 12. Initially, it appeared that a lot of the chatter preemptively declared that iOS 12 would be a day late and dollar short. Last year, we were treated to some marquee features within UIKit like drag and drop — so what could they throw down for us this year?</p><p>But, as is typical, W.W.D.C. brought some new stuff we weren’t expecting, hardening updates and most importantly the new APIs. Exciting times, plus — our apps are just better by virtue of simply running on the new OS. UIKit will always be at the forefront, and this year was no exception as there&#39;s still plenty of discussions left to be had around this year’s improvements.</p><p>Saddle up 📱</p><blockquote>Missed iOS 11’s notable additions from last WWDC? Got you covered <a href="https://medium.com/the-traveled-ios-developers-guide/ios-11-notable-uikit-additions-92e5eb421c3b">here</a>.</blockquote><p><a href="https://www.twitter.com/jordanmorgan10">Jordan Morgan (@JordanMorgan10) | Twitter</a></p><pre>If you enjoyed this week&#39;s post, please feel free to go ahead and NSRecommend(this, where: below);</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b50beb0e3729" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-traveled-ios-developers-guide/ios-12-notable-uikit-additions-b50beb0e3729">iOS 12: Notable UIKit Additions</a> was originally published in <a href="https://medium.com/the-traveled-ios-developers-guide">The Traveled iOS Developer’s Guide</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[WWDC 18: The Pregame Quiz]]></title>
            <link>https://medium.com/the-traveled-ios-developers-guide/wwdc-18-the-pregame-quiz-c7b8f1406f7c?source=rss----79a4c0617ed4---4</link>
            <guid isPermaLink="false">https://medium.com/p/c7b8f1406f7c</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[wwdc]]></category>
            <category><![CDATA[apple]]></category>
            <dc:creator><![CDATA[Jordan Morgan]]></dc:creator>
            <pubDate>Wed, 30 May 2018 20:39:02 GMT</pubDate>
            <atom:updated>2018-12-19T22:42:43.801Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VlGgAvKTLG83jZxpX1rtFg.png" /><figcaption>iOS 12 beckons. Will it be a maintenance release, or a feature rich treasure trove 🤔?</figcaption></figure><h4>The Fourth Annual T.T.I.D.G. quiz is here 🎊</h4><blockquote>A quick note — all of my future posts will be published on my <a href="https://www.swiftjectivec.com/index.html">dedicated website</a> and this publication is no longer being updated. Thanks for reading!</blockquote><p>It’s Christmas time for iOS engineers the world over. Mr.Cook and friends are a little less than a week away from pulling the curtains off of iOS 12. Will we see vast improvements, or the oft rumored “maintenance” release?</p><p>Time will soon tell, but until then it’s time for the fourth annual T.T.I.D.G. WWDC Pregame Quiz!</p><p>If you’d like a quick primer on how this all works or how it got started, check out the first three quizzes from <a href="https://medium.com/the-traveled-ios-developers-guide/wwdc-2015-the-pregame-quiz-420143e2a375">2015</a> ,<a href="https://medium.com/the-traveled-ios-developers-guide/wwdc-2016-the-pregame-quiz-e8f038a025cc">2016</a> and <a href="https://medium.com/the-traveled-ios-developers-guide/wwdc-2017-the-pregame-quiz-4027ee5d68b1">2017</a>.</p><p>Participants — time to add the quiz operation to your queues⚡️!</p><h3>Ground Rules</h3><p>There are three rounds, and the point break down is as follows:</p><ul><li><strong>Round 1</strong>–1 point each answer</li><li><strong>Round 2</strong>- 2 points each answer</li><li><strong>Round 3</strong>- 3 points each answer</li></ul><p>The last question of each round is an optional wildcard question. Get it right, and your team gets <strong>4</strong> <strong>points</strong>, <em>but</em><strong> </strong>miss it and the team will be <strong>deducted 2 points</strong>.</p><h4>Round 1 — Swiftly Answered</h4><p><strong>Question 1:</strong><br>This technique, introduced in a WWDC 15 session, declared that Swift was the industries first <em>what</em> oriented programming language?</p><p><strong>Question 2:</strong><br>On June 2nd, 2014 — what app became the first publicly available app written in Swift?</p><p><strong>Question 3:</strong><br>What’s the name of the instance method that’s <strong>not</strong> possible to use in pure Swift classes/objects that NSObject uses to invoke objc_msgSend and allow for dynamic method resolution?</p><p><strong>Question 4:<br></strong>Which new typealias introduced in Swift 4 extended support of archival and serialization to struct and enum types and enables type-safety for serializing to external formats such as JSON and plist?</p><p><strong>Wildcard:</strong><br>During WWDC 14 when Swift was unveiled, what was the <em>very first</em> public Swift string variable set equal to during its inaugural demo introduction by Chris Lattner?</p><h4>Round 2 — iOS’ &amp; its Tools Storied History</h4><p><strong>Question 1:</strong><br>What framework, added in iOS 5, gave rise to the popularity of photo editing apps by exposing a powerful set of built-in filters for manipulating video and still images?</p><p><strong>Question 2:</strong><br>It’s well known that Core Data, Keyed Archiver and User Defaults allow for persistency on iOS. What other persistency option is available by default on the platform?</p><p><strong>Question 3:</strong><br>What CLI, originally released with Xcode 6 and housed within xcrun, allows one to perform various tasks on the iOS simulator, such as recording videos and opening URL schemes?</p><p><strong>Question 4:<br></strong>Developers sometimes crash their app in a controlled manner during development by invoking the abort(); function, but there is also a little known intrinsic function that generates a machine-specific trap instruction. What is it?</p><p><strong>Wildcard:</strong><br>This ridiculously long initializer, clocking in at 202 characters, is found within what Apple framework:</p><pre>         initWithEnableFan:<br>      enableAirConditioner:<br>      enableClimateControl:<br>            enableAutoMode:<br>        airCirculationMode:<br>             fanSpeedIndex:<br>        fanSpeedPercentage:<br>   relativeFanSpeedSetting:<br>               temperature:<br>relativeTemperatureSetting:<br>               climateZone:</pre><h4>Round 3 — The Random Apple Ones</h4><p><strong>Question 1:</strong><br>This game is a now a triple A blockbuster shooter, but it was originally announced at MacWorld in 1999 and was set to release on the platform as a third person action game. What game is it?</p><p><strong>Question 2:</strong><br>Steve Jobs infamously said that <em>what</em> was a “sweet solution” for developing on the iPhone before the advent of the App Store at WWDC 07&#39;?</p><p><strong>Question 3:</strong><br>The iPhone’s revolutionary multitouch interface was prototyped by a team, colloquially referred to as the ENRI group, at Apple in their abandoned user-testing lab at 2 Infinite Loop — what was their original mission statement?</p><p><strong>Question 4:<br></strong>John Carmack, long a pioneer of the games industry, went toe to toe with Steve Jobs in advocating that which framework should be adopted as the Mac’s 3D Graphics API?</p><p><strong>Wildcard:</strong><br>Though the iPhone’s touchscreen has made the paradigm commonplace in today’s world — Eric Arthur Johnson is believed to have invented the world’s very first touch screen as an engineer at England’s Royal Radar Establishment in 1965. What instrument did he create a touchscreen for?</p><p>And that’s it for this year! You can find the answers right below 👇</p><p>I hope you enjoyed The Traveled iOS Developer’s Guide fourth annual WWDC quiz. Now, onward to WWDC 18!</p><h3>Answer Key</h3><h4>Round 1:</h4><p>1: <a href="http://asciiwwdc.com/2015/sessions/408">A protocol oriented programming language</a><br>2: The WWDC App, this was confirmed in their Platforms State of the Union address during WWDC of that year.<br>3: Good ol’ performSelector:<br>4: Codable<br>Wildcard: <br><a href="https://www.youtube.com/watch?reload=9&amp;v=MO7Ta0DvEWA">The variable “s” was declared as a string set equal to “Hello WWDC!”, showing off Swift’s vastly superior string interpolation API.</a></p><h4>Round 2:</h4><p>1: <a href="https://developer.apple.com/library/content/releasenotes/General/WhatsNewIniOS/Articles/iOS5.html#//apple_ref/doc/uid/TP30915195-SW62">Core Image</a><br>2: SQLite<br>3: <a href="https://medium.com/the-traveled-ios-developers-guide/ios-simulator-power-ups-407060863b3c">simctl</a><br>4: <a href="https://developer.apple.com/library/content/technotes/tn2239/_index.html#//apple_ref/doc/uid/DTS40010638-CH1-SUBSECTION12">__builtin_trap();</a><br>Wildcard: <a href="https://developer.apple.com/documentation/sirikit/insetclimatesettingsincarintent/2102611-init">SiriKit</a></p><h4>Round 3:</h4><p>1: Halo<br>2: <a href="https://daringfireball.net/2007/06/wwdc_2007_keynote">Web Apps</a> (Yikes)<br>3: To “Explore new rich interactions”, hence ENRI<br>4: <a href="https://news.ycombinator.com/item?id=17067129">OpenGL</a> <br>Wildcard: An instrument to help operators improve handling air traffic control.</p><p><a href="https://www.twitter.com/jordanmorgan10">Jordan Morgan (@JordanMorgan10) | Twitter</a></p><pre>If you enjoyed this week&#39;s post, please feel free to go ahead and NSRecommend(this, where: below);</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c7b8f1406f7c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-traveled-ios-developers-guide/wwdc-18-the-pregame-quiz-c7b8f1406f7c">WWDC 18: The Pregame Quiz</a> was originally published in <a href="https://medium.com/the-traveled-ios-developers-guide">The Traveled iOS Developer’s Guide</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[NSPredicate + Objective-C]]></title>
            <link>https://medium.com/the-traveled-ios-developers-guide/nspredicate-objective-c-c745f227df87?source=rss----79a4c0617ed4---4</link>
            <guid isPermaLink="false">https://medium.com/p/c745f227df87</guid>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[xcode]]></category>
            <dc:creator><![CDATA[Jordan Morgan]]></dc:creator>
            <pubDate>Fri, 18 May 2018 20:33:07 GMT</pubDate>
            <atom:updated>2018-12-19T22:43:22.809Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TEdRoHB4KHikVgUtCudxYQ.jpeg" /><figcaption>Yay for open lighted offices.</figcaption></figure><h4>Slice &amp; Dice Collections Effortlessly</h4><blockquote>A quick note — all of my future posts will be published on my <a href="https://www.swiftjectivec.com/index.html">dedicated website</a> and this publication is no longer being updated. Thanks for reading!</blockquote><p>When Swift hit, we were enamored over its simplicity compared to Objective-C. Then it quickly became key to roll with protocol oriented programming. Also, forget reference types and classes. The list goes on.</p><p>And true — those things are great tools and have superb use cases. But I sense they are often lifted up as silver bullets without the necessary amount of thought that should probably be given to architectural decisions.</p><p>So in 2018, the blog posts overfloweth with Swift hackery (even on my blog 🤷🏻‍♂️) and the conference talks wax poetic of its future using functional programming parlance (yup, I’ve done that too 🙋🏻‍♂️).</p><p>Everyone seems excited about working with collections in Swift <strong>but</strong> we’ve also been able to do <em>similar</em> things in Objective-C since iOS 3. So today, I’m chatting about the power of NSPredicate and how you can sift through collections with it using the 🦖.</p><p>I think it’s relevant to bring it back up, as now we’re seeing developers at this point who’ve started with Swift, and then later have circled back to maintain some Objective-C. If that’s you, it’s possible that you’ve been frustrated with the amount of boilerplate or iteration you’ve had to write when using collections in Objective-C.</p><p>Today, I have might have something for you.</p><h4>The Use Case</h4><p>We’ve come a long way in recent years when it comes to Objective-C collections. Not more than a handful of years ago, we had to tell the compiler we were much smarter than it was:</p><pre>NSString *aString = (NSString *)[anArray indexOfObject:0];</pre><p>Thanks Heavens, Cupertino and Friends© eventually tacked on generics by way of type erasure. This marked a significant improvement:</p><pre>NSArray &lt;NSString *&gt; *anArray = @[@&quot;Sup&quot;];<br>NSString *aString = [anArray firstObject];</pre><p>But generics or not, we often interact with the contents of Objective-C collections by doing something like this:</p><pre>for (NSString *str in anArray)<br>{<br>    if ([str isEqualToString:@&quot;The Key&quot;]) <br>    {<br>        // Do something<br>    }<br>}</pre><p>A lot of times, that’s kosher. But as the requirements become more complex and the relationships more varied, the code gets a bit iffy. If you subscribe to the notion that less code means less bugs and better maintenance, the simple act of querying collections can become a bother.</p><p>Predicates can lessen the blow here. It’s not about being “tricky” or cute with our code, but pragmatic and succinct.</p><h4>The 10,000 Foot View</h4><p>At its core, NSPredicate is used to constrain or define the parameters for in memory filtering or when performing a fetch. It really got its bones when paired with Core Data. It’s like SQL, except less awful*.</p><blockquote>* I joke, it’s just that set based operations have never made sense to me 🙃.</blockquote><p>You supply it logical conditions, and it helps to return things that match said conditions. This means it provides support for basic comparisons, compound predicates, key path collections queries, subqueries, aggregates and more.</p><p>As it’s used to sift through collections, you can expect Foundation classes to support it out of the box. Mutable varieties support in-place mutations from the results, whereas their immutable flavors will return a new instance:</p><pre>// In place<br>[mutableArray filterUsingPredicate:/*NSPredicate*/]</pre><pre>// New instance returned<br>[mutableArray filteredArrayUsingPredicate:/*NSPredicate*/]</pre><p>Though predicates can be instantiated from <a href="dash-apple-api://load?topic_id=1409026&amp;language=swift">NSExpression</a> , <a href="dash-apple-api://load?topic_id=1412083&amp;language=swift">NSCompoundPredicate</a> or <a href="dash-apple-api://load?topic_id=1416666&amp;language=swift">NSComparisonPredicate</a> — it can also be created using a string syntax. This is similar to the Visual Format Language that one can use to define layout constraints.</p><p>We’ll be focusing on the utility of using the string syntax method.</p><h4>The Setup</h4><p>To illustrate, let’s consider the following code for the remainder of the post:</p><pre>// Pseudo code <br>Person:NSObject<br>Identifier:NSString<br>Name:NSString<br>PayGrade:NSNumber</pre><pre>// An some property somewhere containing Person instances<br>NSArray &lt;Person *&gt; *employees</pre><h4>Query Time ⚡️</h4><p>What follows for the rest of the post are straight forward examples of how to setup queries using the string format syntax.</p><p>We can start with a simple search scenario. Let’s assume we’ve got an array containing identifiers representing Person objects:</p><pre>{<br>    @&quot;erersdg32453tr&quot;,<br>    @&quot;dfs8rw093jrkls&quot;,<br>    // etc<br>}</pre><p>Now, we’d like to retrieve Person objects from an existing array of Person objects from these identifiers. Using a double nested for-loop, it could be accomplished as such:</p><pre>// Assume &quot;employees&quot; is an existing array of Person objects</pre><pre>NSArray &lt;NSString *&gt; *morningEventAttendees = @[/*Identifiers of people listed above*/];</pre><pre>NSMutableArray &lt;Person *&gt; *peopleAttendingMorningEvent = [NSMutableArray new];</pre><pre>for (NSString *userID in morningEventAttendees)<br>{<br>    for (Person *person in employees)<br>    {<br>        if ([person.identifier isEqualToString:userID])<br>        {<br>           [peopleAttending addObject:person];<br>        }<br>    }<br>}</pre><pre>// Now peopleAttendingMorningEvent has what we want</pre><p>The exact same result is accomplished using a predicate as such:</p><pre>NSPredicate *morningAttendees = [NSPredicate predicateWithFormat:@&quot;SELF.identifier IN %@&quot;, peopleAttendingMorningEvent];</pre><pre>NSArray &lt;Person *&gt; *peopleAttendingMorningEvent = [employees filteredArrayUsingPredicate:morningAttendees];</pre><p>💫.</p><p>Predicate syntax allows for the use of SELF, which is used to great effect here. It represents the object contained within the array being operated on, so for us — Person objects.</p><ul><li><em>Another bonus is that we’ve dropped the mutability of the array definition.</em></li></ul><p>It’s for this reason we can access the key paths associated with the object that SELF is representing. You’re seeing that above, as the identifier property is referenced.</p><p>Should you prefer, any key path can also be expressed via a variable using the “%K” syntax in its place. This version does the same as above:</p><pre>[NSPredicate predicateWithFormat:@&quot;SELF.%K IN %@&quot;, @&quot;identifier&quot;, peopleAttendingMorningEvent];</pre><h4>Compound Predicates</h4><p>It’s trivial to combine comparisons. Suppose our requirements now call for finding users attending events the same way as above, but now their paygrade must also be between 50,000 and 60,000.</p><p>If traditional approaches win out, then our first if statement will only grow:</p><pre>// Same code as above same for this tweak<br>if ([person.identifier isEqualToString:userID] &amp;&amp; (person.paygrade.integerValue &gt;= 5 &amp;&amp; person.paygrade.integerValue &lt;= 10))<br>{<br>    [peopleAttending addObject:person];<br>}</pre><p>But using a refactored predicate gets us there in a more idiomatic way:</p><pre>NSPredicate *morningAttendees = [NSPredicate predicateWithFormat:@&quot;SELF.identifier IN %@ &amp;&amp; SELF.paygrade.integerValue BETWEEN {50000, 60000}&quot;, peopleAttendingMorningEvent];</pre><p>The syntax allows for different operators denoting the same thing which can help hone in on readability, per your preference. For example:</p><ul><li>“&amp;&amp;” or “AND”</li><li>“||” or “OR”</li><li>“!” or “NOT”</li></ul><p>As expected, these are usually aggregated into one predicate by using them in tandem with the basic comparison operators you are likely expecting:</p><ul><li><strong>=,==</strong></li><li><strong>!=,&lt;&gt;</strong></li><li><strong>&gt;=,=&gt;</strong></li><li>&lt;</li><li>&gt;</li><li><strong>&lt;=,=&lt;</strong></li></ul><h4>String Comparisons</h4><p>We’re often tasked with matching values based off of string comparisons. It’s well known that Objective-C shines its unrequited love for verboseness in no greater light than when dealing with NSString:</p><pre>NSString *name = @&quot;Jordan&quot;<br>name = [name stringByAppendingString:[NSString stringWithFormat:@&quot;%@ %@&quot;, @&quot;Wesley&quot;, @&quot;Morgan&quot;]]</pre><p>...whereas Swift just smirks and concatenates its own strings with much less fuss. As such, we can take heart that such verboseness doesn’t apply with NSPredicate and string comparisons.</p><pre>// Assume mutablePersonAr is a Person array with names of &quot;Karl&quot;, &quot;Jordan&quot;<br>NSPredicate *namesStartingWithK = [NSPredicate predicateWithFormat:@&quot;SELF.name BEGINSWITH &#39;K&#39;&quot;];</pre><pre>// Now only contains Karl<br>[mutablePersonAr filterUsingPredicate:namesStartingWithK];</pre><p>Virtually any comparison can be achieved by way of the predicate syntax’s CONTAINS, BEGINSWITH, ENDSWITH and LIKE:</p><pre>// Assume mutablePersonAr is a Person array with names of &quot;Karl&quot;, &quot;Kathryn&quot;<br>NSPredicate *namesStartingWithK = [NSPredicate predicateWithFormat:@&quot;SELF.name LIKE &#39;Kar*&#39;&quot;];</pre><pre>// Now only contains Karl<br>[mutablePersonAr filterUsingPredicate:namesStartingWithK];</pre><blockquote>You may have noticed the asterisk above, which like many similar DSLs out there, represents a wildcard.</blockquote><p>The ease of use really begins to come to the forefront when you combine comparison operators within one query:</p><pre>NSString *predicateFormat = @&quot;(SELF.name LIKE &#39;Kar*&#39;) AND (SELF.paygrade.intValue &gt;= 10)&quot;</pre><pre>NSPredicate *namesStartingWithK = [NSPredicate predicateWithFormat:predicateFormat];</pre><pre>// Now only contains Karl<br>[mutablePersonAr filterUsingPredicate:namesStartingWithK];</pre><p>Further, there is even support for a mix of NSPredicate’s SQLish syntax to be mashed up with regular expressions by way of the MATCHES syntax:</p><pre>[NSPredicate predicateWithFormat:@&quot;SELF.phoneNumber MATCHES %@&quot;, phoneNumberRegex];</pre><p>However, this is an opportune time to point out that the predicate format syntax is exactly what it is. A straight up string. And unless you’re Mavis Beacon, you’ll supply it with a typo every now and again.</p><p>The good news is that’ll you find out fast — as a runtime exception awaits. What we gain in power and flexibility is, in some ways, mitigated by the loss of the safety net that static analysis provides.</p><p>To illustrate, this slightly refactored sample from above will crash. Can you tell why?</p><pre>NSString *predicateFormat = @&quot;SELF.name LIKE &#39;Kar*&#39;) AND (SELF.paygrade.intValue &gt;= 10)&quot;</pre><pre>NSPredicate *namesStartingWithK = [NSPredicate predicateWithFormat:predicateFormat];</pre><pre>// Now only contains Karl<br>[mutablePersonAr filterUsingPredicate:namesStartingWithK];</pre><p>To combat such issues, I’ve often paired predicates with NSStringFromSelector() to provide an additional layer of safety against typos and future refactoring:</p><pre>NSString *predicateFormat = @&quot;(SELF.%@ LIKE &#39;Kar*&#39;) AND (SELF.paygrade.intValue &gt;= 10)&quot;</pre><pre>NSString *kpName = NSStringFromSelector(@selector(identifier));<br>NSString *kpPaygrade = NSStringFromSelector(@selector(paygrade));</pre><pre>NSPredicate *namesStartingWithK = [NSPredicate predicateWithFormat:predicateFormat, kpName, kpPaygrade];</pre><pre>// Now only contains Karl<br>[mutablePersonAr filterUsingPredicate:namesStartingWithK];</pre><p>A bit more heavy handed? Sure. Safer? Absolutely.</p><h4>KeyPath Collection Queries</h4><p>Building upon the use of key paths, NSPredicate boasts a full suite of tools to operate on them in the name of a better search. Consider the following:</p><pre>// Assume a Person object now has this property on it:<br>// NSArray &lt;NSNumber *&gt; *previousPay</pre><pre>// Find everyone who&#39;s average previous pay was over 10<br>NSString *predicateFormat = @&quot;SELF.previousPay.@avg.doubleValue &gt; 10&quot;;</pre><pre>NSPredicate *previousPayOverTen = [NSPredicate predicateWithFormat:predicateFormat];</pre><pre>// Everyone whose previous pay&#39;s average was greater than 10<br>[mutablePersonAr filterUsingPredicate:previousPayOverTen];</pre><p>You could switch our the @avg for:</p><ul><li>@sum</li><li>@max</li><li>@min</li><li>@count</li></ul><p>When you consider the amount of, albeit trivial, code that you might’ve had to author to achieve the same things outside of a predicate, these types of techniques can begin to become part of your regular toolchain.</p><h4>Digging Deeper into Arrays</h4><p>Much like key path queries, there is also support for inspecting implicit arrays to a finer degree:</p><ul><li>array[FIRST]</li><li>array[LAST]</li><li>array[SIZE]</li><li>array[index]</li></ul><p>Building from the code sample above, this allows for queries such as this:</p><pre>// Find everyone who&#39;s had three previous different salaries<br>NSString *predicateFormat = @&quot;previousPay[SIZE] == 3&quot;;</pre><pre>NSPredicate *threePreviousSalaries = [NSPredicate predicateWithFormat:predicateFormat];</pre><pre>// These Person objects had three previous salaries<br>[mutablePersonAr filterUsingPredicate:threePreviousSalaries];</pre><p>And as we alluded to above, it’s perfectly find to apply multiple conditions:</p><pre>// Find everyone who&#39;s had three previous different salaries and whose first one was greater than 8<br>NSString *predicateFormat = @&quot;(previousPay[SIZE] == 3) AND (previousPay[FIRST].intValue &gt; 8)&quot;;</pre><pre>NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateFormat];</pre><pre>[mutablePersonAr filterUsingPredicate:predicate];</pre><p>Going even further, you get gain even more power by using either of the following:</p><ul><li><strong>@distinctUnionOfArrays</strong></li><li><strong>@unionOfArrays</strong></li><li>@<strong>unionOfObjects</strong></li><li><strong>@distinctUnionOfObjects</strong></li></ul><p>Hang with me, but assume we had an array of arrays containing Person objects, and all that we needed were the unique identifiers of the Person instances among them:</p><pre>// Assume p1/2/3/4 are all hydrated Person objects<br>NSArray &lt;NSArray &lt;Person *&gt; *&gt; *previousEmployees = @[@[p1],@[p2,p1,p2],@[p1],@[p4,p2],@[p4],@[p4],@[p1]];</pre><pre>// Get every unique ID<br>NSArray *unqiuePreviousEmployeeIDs = [previousEmployees valueForKeyPath:@&quot;@distinctUnionOfObjects.identifier&quot;];</pre><pre>// The array would contain only unique IDs</pre><p>Cool, no?</p><p>The fun doesn’t stop there, as there is even support for subqueries:</p><pre>// Assume Person objects have a new property for their team:<br>// NSArray &lt;Person *&gt; *team;</pre><pre>// Find everyone in an employee array who has people in their team with a pay over 1 and no previous pay history<br>NSString *predicateFormat = @&quot;SUBQUERY(team, $teamMember, $teamMember.paygrade.intValue &gt; 1 AND $teamMember.previousPay == nil).@count &gt; 0&quot;;</pre><pre>NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateFormat];</pre><pre>[employeeAr filterUsingPredicate:predicate];</pre><p>Subqueries are quite useful should you find yourself needing to search on an array of objects which also contain a property that’s itself a collection. So here, we’ve got an array of Person objects, and we’re peeking into their teamMember array.</p><h4>Convenience is Key(Path)</h4><p>Though NSPredicate is built for search, it wouldn’t be Objective-C if you couldn’t bend things from their exact purpose <em>just</em> a tad. No exception here.</p><p>When you think of a predicate, you think of filtering down a collection — meaning the return (or in place mutation) still contains the same stuff.</p><p>But you can, well, make it <em>not</em> be the same things. And we actually did that in the previous code sample. The array of arrays above was used to return an array of identifiers — NSString instances. Keypathin’ makes it all possible.</p><p>Here’s a more direct example:</p><pre>// We want an array of identifier strings whose length is greater than 10<br>NSString *predicateFormat = @”SELF.identifier.length &gt; 10&quot;;</pre><pre>NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateFormat];</pre><pre>NSArray &lt;NSString *&gt; *longEmployeeIDs = [[employeeArray filteredArrayUsingPredicate:predicate] valueForKey:@”identifier”];</pre><pre>// Now longEmployeeIDs has not Person objects, but only strings</pre><h4>Wrapping Up</h4><p>You can burn through Objective-C collections with sugary syntax. You can drill down to a particular subset of items without nested loops. It’s all much easier on the eyes with NSPredicate.</p><p>While Swift has first class language support to slice and dice collections, it’s really not much of a bother to utilize an object created to do much of the same things. Should you find yourself in a mature codebase or a newly minted one sporting The Dino (Objective-C), let the predicates flow freely.</p><p>Until next time✌️.</p><p><a href="https://www.twitter.com/jordanmorgan10">Jordan Morgan (@JordanMorgan10) | Twitter</a></p><pre>If you enjoyed this week&#39;s post, please feel free to go ahead and NSRecommend(this, where: below);</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c745f227df87" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-traveled-ios-developers-guide/nspredicate-objective-c-c745f227df87">NSPredicate + Objective-C</a> was originally published in <a href="https://medium.com/the-traveled-ios-developers-guide">The Traveled iOS Developer’s Guide</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[UILayoutGuide]]></title>
            <link>https://medium.com/the-traveled-ios-developers-guide/uilayoutguide-6b3b552b1890?source=rss----79a4c0617ed4---4</link>
            <guid isPermaLink="false">https://medium.com/p/6b3b552b1890</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[app-development]]></category>
            <dc:creator><![CDATA[Jordan Morgan]]></dc:creator>
            <pubDate>Sun, 15 Apr 2018 02:12:54 GMT</pubDate>
            <atom:updated>2018-12-19T22:43:41.172Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yWXsm8BqdqlttJJ8VdsITw.jpeg" /><figcaption>Are you pro MacBook sticker on the lid or no?</figcaption></figure><h4>User Interface Creation Made Responsible</h4><blockquote>A quick note — all of my future posts will be published on my <a href="https://www.swiftjectivec.com/index.html">dedicated website</a> and this publication is no longer being updated. Thanks for reading!</blockquote><p>It’s astounding to think that we lived in a pre Auto Layout world not that long ago. Auto resizing masks and CGRectMake() ruled the lands of user interface development for quite some time.</p><p>But as Apple’s devices started stacking up various point sizes, it was obvious that developers would either languish in the pit of misery that can result from too many frame calculations or embrace the power of describing relationships. The latter, obviously, won out.</p><p>And thus, Auto Layout has been <a href="https://oleb.net/blog/2014/03/how-i-learned-to-stop-worrying-and-love-auto-layout/">used</a>, <a href="https://github.com/SnapKit/Masonry">DSL</a>’d and <a href="https://www.reddit.com/r/iOSProgramming/comments/4t6kd5/why_i_dont_use_autolayout/">criticized</a> ever since. With its rise, though, another layout paradigm also came into prominence. The “spacer” view. Or dummy view. Container view.</p><p>Whatever you call it, we’ve all used them. But Apple, as so it often does, says there is a better way. This week, let’s chat UILayoutGuide.</p><h4>But Dummy Views Rock (…and I agree)</h4><p>Dummy views solve some layout problems extremely well. That’s why we all use(d) them. Expressing inter-view relationships, creating modular chunks of your user interface or defining constraints to express the coordinates or size of empty spaces between views all called for the dummy view.</p><p>In fact, even if one simply wished to center a group of controls in a particular coordinate space, a dummy view was often used to contain them.</p><p>As such, a lot of important jobs were all entrusted to a construct that was never meant to truly do any of them. If you contest that notion, ask yourself what a view actually does in an iOS application.</p><p>Or better yet, let the docs tell the story:</p><blockquote>A view object renders content within its bounds rectangle and handles any interactions with that content.</blockquote><blockquote>A view is a subclass of UIResponder and can respond to touches and other types of events.</blockquote><p>So it’s hardly disputible to reason that an important part of a view being a view is to render stuff and handle events. Dummy views, views though they are — shouldn’t particpate in any of those activities at best and <em>do</em> participate in some of them at worst.</p><p>Using dummy views, we’ve</p><ul><li>Incurred the cost of a view that’s only helping to define a layout.</li><li>Added a first class member of the view hierarchy, joining in on all the overhead that may be associated with any task related to it.</li><li>And as part of the responder chain, it could intercept some messages that it was never intended to handle.</li></ul><p>😬.</p><h4>There, but Not Really</h4><p>But a layout guide is none of those things, nor does it suffer from any of those problems. It’s a non-rendering view, much like its more powerful cousin, <a href="https://medium.com/the-traveled-ios-developers-guide/uistackview-a-field-guide-c1b64f098f6d">UIStackView</a>.</p><p>Unlike a bonafide view, a layout guide actually doesn’t define a view. Instead, it just represents a retangular region in their owning view’s coordinate system. That’s it. This is what allows it to interact with Auto Layout.</p><p>The API closely, and purposely, mirrors that of a view:</p><pre>let scrollView = UIScrollView()</pre><pre>// Instead of this...<br>let containerView = UIView()<br>scrollView.addSubview(containerView)</pre><pre>containerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true<br>containerView.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true<br>containerView.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true<br>containerView.rightAnchor.constraint(equalTo: scrollView.rightAnchor).isActive = true</pre><pre>// We can do this...<br>let containerLayoutGuide = UILayoutGuide()<br>scrollView.addLayoutGuide(containerLayoutGuide)</pre><pre>containerLayoutGuide.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true<br>containerLayoutGuide.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true<br>containerLayoutGuide.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true<br>containerLayoutGuide.rightAnchor.constraint(equalTo: scrollView.rightAnchor).isActive = true</pre><h4>API Particulars</h4><p>The UILayoutGuide class is designed to perform all the tasks previously performed by dummy views, but to do it in a safer, more efficient manner.</p><p>Layout guides do not define a new view. They do not participate in the view hierarchy. Instead, they simply define a rectangular region in their owning view’s coordinate system that can interact with Auto Layout.</p><p>The flow, shown above, is straightforward:</p><ul><li>Instantiate a layout guide.</li><li>Invoke addLayoutGuide(_:)to the desired view.</li><li>Set up valid constraints on the layout guide.</li></ul><p>Let’s imagine you needed to constrain some views and center them, but only in the bottom left corner of a view. As in, if you cut the view into four corners, we want to add stuff to the bottom left one. Layout guide makes this easy as it was with dummy views without the baggage:</p><pre>let bottomLeftGuide = UILayoutGuide()<br>view.addLayoutGuide(bottomLeftGuide)</pre><pre>// External Constraints<br>bottomLeftGuide.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true<br>bottomLeftGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true<br>bottomLeftGuide.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5).isActive = true<br>bottomLeftGuide.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5).isActive = true</pre><pre>// Internal constraints, pseudo code for brevity<br>someLabel.top.equalToLayoutGuideTop<br>someLabel.left/right/etc</pre><pre>// And you can pin all the other views here that you need</pre><p>Layout guides solve a particular problem so well that Apple has been laying them down on you for the last several releases of iOS, but you may not have actually noticed. Top layout guide, safe area layout guide — you’re likely familiar with these already.</p><p>If I wasn’t such a bleeding heart for writing words about coding stuff, I could’ve let this blog begin and end with one sentence: A layout guide can be used entirely like a dummy view but it doesn’t clog your view hierarchy or respond to events.</p><p>But where is the fun in that 😛?</p><p>If you want a few extra neat tidbits about layout guide, read on.</p><h4>For De🐛-Ing</h4><p>Look, Auto Layout goes to hell every now and again no matter what happens. You can either fight the wall of text spit out to the console or run and hide from it. If you opt for the former, take note of layout guide’s identifier property.</p><pre>bottomLeftLayoutGuide.identifier = “BottomLeftGuide”</pre><p>When things go sideways, you at least know if your layout guide is part of the issue (which is half of the battle):</p><pre><strong>// When constraints break, it’ll show in the logs similar to this<br>“&lt;NSLayoutConstraint:0x6040002b8a80 UILabel:0x7fbb1a39dde0.left == BottomLeftGuide:0x6040001ae2a0.left + 16&gt;”</strong></pre><p>Take note that the prefix of “NS” and “UI” are system reserved, and UIKit uses these for the layout guides that it creates.</p><p>Another technique that you can use is to query a layout guide’s layoutFrameat runtime. There are times when one must mix both a frame based approach and Auto Layout within the same view hierarchy and this can help immensely.</p><pre>CGRect guideRect = someLayoutGuide.layoutFrame<br>aNonAutoLayoutView.frame = CGRectMake(0, guideRect.size.height, 100, 100)</pre><p>Remember here though, because the layout frame is derived from Auto Layout, you’ll need to ensure the constraints have been installed before this property is of any use to you. By the time the layout guide’s owning view has called layoutSubviews — this will have the expected results.</p><p>Further, if you need to continue down the layout debugging path you may find the following two components are what you need:</p><ul><li>The constraintsAffectingLayout:for:) function</li><li>And the hasAmbigiousLayout property</li></ul><p>Using the function above, you can see all the constraints for a given axis (i.e. vertical or horizontal). Use it to see if there are any unexpected constraints influencing it:</p><pre>let constraintsEffectingVertical:[NSLayoutConstraint] = bottomLeftGuide.constraintsAffectingLayout(for: .horizontal)</pre><p>Lastly, the boolean property acts exactly how it’s named. It’s utility lies in the fact that you can easily check for ambigious constraints on <em>just </em>the layout guide using a symbolic breakpoint. If you are like me, sometimes you want the show to come to a total halt if something like this happens. I sometimes wrap this in an NSAssert() in my own side projects so I have to deal with the issue right away.</p><h4>Winding Down</h4><p>If brevity is the source of wit, then the layout guide may be the sharpest of them all nesteled inside UIKit. It’s insanely simple — just a plain old thing that looks like a view, smells like a view, acts like a view and….isn’t a view. It’s just a rectangular region that loves Auto Layout.</p><p>And in so many cases, that’s all a developer needs. So next time you feel yourself reaching for a spacer view, opt to embrace the simplicity and safety of UILayoutGuide.</p><p>Until next time ✌️.</p><p><a href="https://www.twitter.com/jordanmorgan10">Jordan Morgan (@JordanMorgan10) | Twitter</a></p><pre>If you enjoyed this week&#39;s post, please feel free to go ahead and NSRecommend(this, where: below);</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6b3b552b1890" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-traveled-ios-developers-guide/uilayoutguide-6b3b552b1890">UILayoutGuide</a> was originally published in <a href="https://medium.com/the-traveled-ios-developers-guide">The Traveled iOS Developer’s Guide</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Techniques to Connect Websites to iOS Apps]]></title>
            <link>https://medium.com/the-traveled-ios-developers-guide/techniques-to-connect-ios-apps-to-their-websites-541b366a8aee?source=rss----79a4c0617ed4---4</link>
            <guid isPermaLink="false">https://medium.com/p/541b366a8aee</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[apple]]></category>
            <dc:creator><![CDATA[Jordan Morgan]]></dc:creator>
            <pubDate>Sat, 03 Feb 2018 05:38:51 GMT</pubDate>
            <atom:updated>2018-12-19T22:44:04.679Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aTkVj8aUrzmNSxlg5mzscw.jpeg" /><figcaption>I do enjoy this stock photo, though I question the authenticity of paper notebook and if it was really being used 🤔</figcaption></figure><h4>Curry favor with users by making things easy</h4><blockquote>A quick note — all of my future posts will be published on my <a href="https://www.swiftjectivec.com/index.html">dedicated website</a> and this publication is no longer being updated. Thanks for reading!</blockquote><p>Developing for the web feels like a world that’s simply left me behind. I made a concerted effort to double down on iOS development several years ago. I’ve never looked back or regretted it, and I don’t even know what the rear view mirror looks like. It’s caked in dust by this point, no doubt.</p><p>Though I’ve <a href="https://medium.com/the-traveled-ios-developers-guide/swift-javascript-32eca7cf69a6">mentioned web related things here before</a>, the last time I did any meaningful web development in a professional context, I was using JQuery v4.x.</p><p>So, yeah — it’s been a few years and (seemingly) several thousand Javascript frameworks later. I don’t venture into that ecosystem much, and my last trips were on account of the things I’m about to mention here.</p><p>Which is, there are some incredibly trivial things one can do on their website to couple it to their iOS app counterpart. If you have the next thirty minutes free, I’d wager you could do all of them listed here.</p><p>Let’s rock 🤘</p><h4>Give your SaaS some sass</h4><p>First, what’s the end game here? To simply leverage some hosted .json files on your server and put meta tags in your markup to allow users to jump straight into your app or display information about it more effectively. That’s it.</p><p>This stuff is typically key for SaaS business’ or solopreneurs because in the world we live in, where there is a SaaS website a (hopefully) native app will follow. We want to help them dance together.</p><p>It helps that iOS 11 built features specifically for this. Open up your camera, point it at a QR code. Boom — iOS shows us the actionable details. Share a link in messages. Get a rich text preview. The list goes on.</p><h4>QR Code Detection</h4><p>Let’s start with everyone’s favorite technology, quick response codes.</p><pre>//TODO: (insert QR code joke here)</pre><p>Creating a QR code that users can point to and then be prompted to download, open or route to a part of your app can be useful. Doing so can be accomplished by setting up an apple-app-site-association JSON file with an “applinks” key value pair and hosting it. You may already have this file for hand off support.</p><p>For this purpose, it looks like this:</p><pre>{<br>    &quot;applinks&quot;: {<br>        &quot;apps&quot;: [],<br>        &quot;details&quot;: [<br>            {<br>                &quot;appID&quot;:&quot;DJGHSDJGH24.com.blogPost.yolo&quot;,<br>                &quot;paths&quot;: [&quot;*&quot;]<br>            }<br>        ]<br>    }</pre><pre>}</pre><blockquote>The appID key simply must be your team or app ID,(.), followed by your bundle ID.</blockquote><p>An easy place for the JSON file to live is typically in the .well-known subdirectory:</p><pre>https://wwww.anExample.com/.well-known/apple-app-site-association</pre><p>Additionally, planting it at the root of your server works just fine too.</p><p>If you host such a file, the end result is that your app will immediately show to open via a notification when the user points at the QR code. The only metadata your QR code needs is the URL for your website.</p><p>No external QR code download, no more taps — nothing. It just happens.</p><p>If the user doesn’t have your app, Safari will kick in instead, taking them to your website.</p><h4>Getting Particular</h4><p>You have the ability to specify a few things within your applinks key-value pairs. Let’s look at what’s available:</p><ul><li><strong>apps</strong> — You supply an empty array here. I would tell you why, but I would be making it up because Apple literally says nothing else about it besides that so…¯\(°_o)/¯</li><li><strong>details</strong> — An array of dictionaries, one for each app that your site ultimately supports. Ordering matters in the array, as iOS look up links according to it. This allows you to specify an app to handle a certain part of your website.</li><li><strong>details[appid]</strong> — The team ID or app ID with a period, and your app’s bundle ID tacked on.</li><li><strong>details[paths] </strong>— An array or strings that determine which parts of your website are supported by the app. Additionally, you can say which parts <strong>aren’t </strong>supported.</li></ul><p>The first three entries don’t merit much more discussion. The paths entry does have some nifty options for excluding content where applicable.</p><p>For example, including “NOT ” at the beginning of the path will basically blacklist that content from being used as a universal link:</p><pre>{<br>    &quot;applinks&quot;: {<br>        &quot;apps&quot;: [],<br>        &quot;details&quot;: [<br>            {<br>                &quot;appID&quot;:&quot;DJGHSDJGH24.com.blogPost.yolo&quot;,<br>                &quot;paths&quot;: [&quot;/posts/iOS&quot;,<br>                          &quot;NOT /oldPosts/outdated/*&quot;]<br>            }<br>        ]<br>    }</pre><pre>}</pre><p>This works much like regex, with support for wildcards:</p><pre>{<br>    &quot;applinks&quot;: {<br>        &quot;apps&quot;: [],<br>        &quot;details&quot;: [<br>            {<br>                &quot;appID&quot;:&quot;DJGHSDJGH24.com.blogPost.yolo&quot;,<br>                &quot;paths&quot;: [&quot;/posts/iOS&quot;,<br>                          &quot;/oldPosts/201?/*&quot;]<br>            }<br>        ]<br>    }</pre><pre>}</pre><p>A few random words of advice:</p><ul><li>Keep in mind these matches are case sensitive.</li><li>If you’re rocking a few domains, you’ll need to roll anapple-app-site-association file for each one that your app supports. Example: apple.com would have different motives than someProducts.apple.com</li><li>One doesn’t actually need to appended “.json” to the JSON file. Don’t ask me how I know this, or how much hypothetical time was lost to it.</li><li>If you associate several apps within one apple-app-site-association file, iOS will handle it by presenting an alert showing each one to determine which is opened. The next time this happens, iOS will suggest the last choice as a default — but users can still switch this via a force touch or by pulling down on the notification.</li><li>Safari handles all of this as well. If you hosted the QR code as an image, and an iOS user 3D touches on it — this exact same flows happens.</li></ul><h4>Associated Domains</h4><p>As an iOS developer, you’ve got some duties too. Chief among them is to let Xcode know you’re expecting this to happen. This is done by the “Associated Domains” capability for your app binary.</p><p>Flip it on within Xcode and add some entries for each one you wish to support. Again, you might’ve spent time here already if you’ve developed for hand off capabilities.</p><p>For this particular type of routing, though, it would look like this:</p><pre>// i.e. applinks:&lt;domain&gt;<br>applinks:anExample.com</pre><p>As we’ll see later, this creates a handshake of sorts that confirms both the app and website trust one another. Xcode will generate an entitlement to reconcile the security aspect and apply it on your app’s behalf. Spoiler alert, this opens up the door for quick credential retrieval too, as we’ll see later.</p><p>Of course, this means you’ll need to handle the user activity passed to you within your app delegate. But, that’s a blog post for another day.</p><p>Using universal app links is great, and I hope more apps use it as time goes on. They can happen outside of a QR code context too. They enjoy certain advantages over custom URL schemes in that they are more secure due to the handshake, they can’t be hijacked or claimed by any other app and the only party who can associate one to your app, is you.</p><h4>Web Credentials</h4><p>This nifty trick is absolutely essential for you if your app has a log in mechanism or any user portal system online. By employing password autofill, users can tap on the lock icon in the quicktype bar that appears over the keyboard, authenticate and then have their information automatically filled out.</p><p>It’s beautiful, and I use it daily.</p><p>To allow for this to happen, there is minor housekeeping that you need to do for the text fields or text views representing your log in. Simply assign the correct values added in iOS 11 to their textContentType property so iOS knows what goes where:</p><pre>loginField.textContentType = .username<br>passwordField.textContentType = .password</pre><p>That’s all it takes from a coding standpoint — nothing more than assigning to a property (if you don’t, you leave it up to iOS’ heuristics to make the assumptions). There’s nothing left other than to respond accordingly to the incoming “did change” delegate methods or notifications that’ll be fired off with the credentials.</p><p>Technically, you could stop here and things would work….<em>ish</em>.</p><p>Users would just get the quick type bar, but your site’s credentials wouldn’t be offered up within it. They’d just see the lock icon, then have to auth up, search for it and select it.</p><p>Amateur hour. Obviously, we’d prefer the user’s credentials to show up immediately once either one of those text controls becomes first responder.</p><h4>Establishing Trust, Again</h4><p>Which brings us back to our apple-app-site-association file.</p><p>Going deeper into the same thought above, a signed entitlement tells iOS which sites you are associated with. The secure, two way link is established in particular when your app is installed or updated. At that point iOS does a wellness check by traversing your domains listed within your Associated Domains (which we mentioned above) and pings each one to see if it gets a valid association file.</p><p>If the app points to the website and the website points to the app — we’re cooking.</p><p>The entry under Associated Domains for password autofill looks a bit different than the above app links we entered before, as it’s prefixed with “webcredentials”:</p><pre>webcredentials:anExample.com</pre><blockquote>XCode gonna’ Xcode. If you’re still seeing an error at this point, you might need to hop over to the developer portal and enable Associated Domains for your app ID.</blockquote><p>As you’ve likely keyed in on, the Associated Domains entries follow the same pattern of including a service (i.e. activitycontinuation, applinks, etc) and domain:</p><pre>&lt;service&gt;:&lt;fully qualified domain&gt;[:port number]</pre><p>From there, it’s a case of adding that to your association file:</p><pre>{<br>    &quot;applinks&quot;: {<br>        &quot;apps&quot;: [],<br>        &quot;details&quot;: [<br>            {<br>                &quot;appID&quot;:&quot;DJGHSDJGH24.com.blogPost.yolo&quot;,<br>                &quot;paths&quot;: [&quot;/posts/iOS&quot;,<br>                          &quot;/oldPosts/201?/*&quot;]<br>            }<br>        ]<br>    },<br>    &quot;webcredentials&quot;: {<br>        &quot;apps&quot;: [&quot;DJGHSDJGH24.com.blogPost.yolo&quot;]<br>    }<br>}</pre><p>The only key to worry about is “apps”, which is just an array of strings (their value constructed the same way as above with app links) that represent the apps your site provides log in information for.</p><p>Once you throw that up on your site — the entire web credentials and password autofill pipeline is all set. I can’t tell you how much times this saves from a user perspective. It goes up by an order of magnitude if one uses Safari’s password suggestions as well.</p><h4>Image Links</h4><p>Sharing links within Messages is a ubiquitous practice among iOS users. Nothing is more rewarding than tapping on the link cards, with their inviting .png hero images sitting there beckoning us to load up a website within Safari.</p><p>Except when that doesn’t happen, and it’s just plain text 😬.</p><p>This is so easy to avoid, though, as you easily can control the title, icon, image and even video that displays. Using the <a href="http://ogp.me">open graph protocol</a>, you can supply all of this stuff inside your site’s &lt;head&gt; tag.</p><p><strong>Title (if this isn’t present, it’ll take your site’s title):</strong></p><pre>// Just in case, Javascript isn&#39;t run when generating rich links - so the value needs to be in the source. They can&#39;t be created dynamically.<br>&lt;meta name=&quot;og:title&quot; content=&quot;The Title&quot; /&gt;</pre><p><strong>Icons (derived from a favicon or apple touch icon if it’s there. If not, you can roll with something like this):</strong></p><pre>&lt;link rel=&quot;icon&quot; href=&quot;path/to/icon&quot; type=&quot;image/png&quot; /&gt;</pre><p><strong>Image (replaces the icon if present, but still provide both because sometimes Messages prefers the icon over an image in situations like poor networking conditions)</strong></p><pre>&lt;meta name=&quot;og:image&quot; content=&quot;path/to/image.png&quot; /&gt;</pre><p><strong>Video (of note, you can supply a URL to a YouTube video, which is the only video player network that’ll work if you don’t use a file iOS can natively play)</strong></p><pre>&lt;meta name=&quot;og:video&quot; content=&quot;path/to/video.mp4&quot; /&gt;</pre><p>That’s all it takes to get the pretty, informational rich links when your website is shared within Messages. Nice.</p><h4>The “You probably are already doing this but I’ll add it anyways” Paragraph</h4><p>Smart banners. At this point, you’re probably using them.</p><p>But just in case you aren’t, add a meta tag with your app ID to take care of it. When potential users visit your site, they’ll get that call to action banner at the top to download it.</p><p>If you’re wanting to hunt down your app ID quickly, just visit <a href="http://itunes.apple.com/linkmaker/">iTunes Link Maker</a>. The entire meta tag can be as simple as this:</p><pre>&lt;meta name=&quot;apple-iunes-app&quot; content=&quot;app-id=123456789&quot;&gt;</pre><p>If you need to, you can also include an iTunes affiliate string and app argument parameter to deep link to a specific controller to keep context consistent with where a user might be on your website.</p><p>Generally, though, this is tacked on your landing page and that’s good enough to serve its purpose. Now, go forth and take back what could’ve been just an ephemeral thought about your app and convert it to an install 💪.</p><h4>Wrapping Up</h4><p>The lot of us craft software for our 9–5 and craft software to scratch our own creative itch. Eventually, all roads lead to a website talking about one or the other. Do them both justice, step away from Xcode and throw up a json file or two or include some simple meta tags that could help slip users right into your beautiful code.</p><p>Things like this are almost like the chore list for iOS engineers. We may not think about them first, we may not wake up to crank out config files — but hey, they can help our endgame and move the needle towards exposure. So why not?</p><p>Until next time ✌️</p><p><a href="https://www.twitter.com/jordanmorgan10">Jordan Morgan (@JordanMorgan10) | Twitter</a></p><pre>If you enjoyed this week&#39;s post, please feel free to go ahead and NSRecommend(this, where: below);</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=541b366a8aee" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-traveled-ios-developers-guide/techniques-to-connect-ios-apps-to-their-websites-541b366a8aee">Techniques to Connect Websites to iOS Apps</a> was originally published in <a href="https://medium.com/the-traveled-ios-developers-guide">The Traveled iOS Developer’s Guide</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[NSMeasurement]]></title>
            <link>https://medium.com/the-traveled-ios-developers-guide/nsmeasurement-2be0d84bda64?source=rss----79a4c0617ed4---4</link>
            <guid isPermaLink="false">https://medium.com/p/2be0d84bda64</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Jordan Morgan]]></dc:creator>
            <pubDate>Sun, 17 Dec 2017 20:27:50 GMT</pubDate>
            <atom:updated>2018-12-19T22:44:22.314Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*avIiRrRmNO1c5y2U_fdjzg.jpeg" /><figcaption>My stock photos game is starting to suffer. I think I was supposed to put images in the green screens 😐.</figcaption></figure><h4>Foundation’s Powerful API to Measure #AllTheThings 📐</h4><blockquote>A quick note — all of my future posts will be published on my <a href="https://www.swiftjectivec.com/index.html">dedicated website</a> and this publication is no longer being updated. Thanks for reading!</blockquote><p>Measuring units, things or items in software won’t always be the most glamorous job for software engineers. Though not as thrilling as writing performant user interface libraries nor as fulfilling as conjuring up networking code that weaves concurrent execution with ease, measuring units in iOS is still done more often than not, wrong.</p><p>How can one author such code in an internationlized manner and not in a precipitous one? Foundation, as is so often the case, holds the answer. And it has since iOS 10.</p><p>This week, let’s look at NSMeasurement and friends.</p><h4>More Common than You Think</h4><p>Software has always had situations that crop up which present users with several things that are either measurable or generally quanitifiable. And when that software (iOS) runs on billions of devices across the globe, the need to represent internationalized values of those things becomes not only more important, but quite key.</p><p>Getting such measurements and units right isn’t a baseline experience, you should just expect it of your software.</p><p>So with that- these APIs aid not only just with the obvious “converter” apps, but also with games, shopping lists and everything else in between:</p><ul><li>Are you representing a measurement of time ⌚️?</li><li>A distance traveled 🚙?</li><li>The rate at which we traveled 🗺?</li><li>The weight of an object ⚖️?</li></ul><p>As such, the temptation to use a simple double type makes sense on the surface level and simply breaks apart anywhere else:</p><pre>//Technically we even set up the variable name for failure<br>let milesTraveled:Double</pre><h4>NSMeasurement and all his Units</h4><p>Following the previous example, what we really need is an accurate, bonafide construct to represent a measurement. And while miles is certainly a measurement, it’s only one that generally makes sense within the context of Murica’ 🇺🇸. As such, Foundation’s support for a measurement is tactfully generic:</p><pre>public struct Measurement &lt;UnitType:Unit&gt;</pre><blockquote>Note that within the text, for stylistic purposes and because I code in Objective-C daily, I’ll refer to the frameworks with their NS prefix. All of these objects are properly bridged over to Swift as value types and structs.</blockquote><p>It provides a way to provide a generic <em>unit</em> of measurement and also a value that corresponds to it. Its initializer will ask for both:</p><pre>public init(value:Double, unit:UnitType)</pre><p>Every unit will always have a symbol, though not every unit has a dimension nor will they always be equivalent to one another. It’s something to note, sure, but one will most likely work with dimensional units. But, it’s for this reason that NSUnit’s designated initializer will require only a symbol:</p><pre>public class Unit: NSObject, NSCopying<br>{<br>    public let symbol:String<br>    public init(symbol: String)<br>}</pre><p>When it comes to NSMeasurement, this unit type drives the majority of the work, and you can define which to use via its initializer, but more commonly you’ll use an NSDimension (which subclasses NSUnit) provided to us by Apple. Each dimensional unit will then drive down further into a given dimension that exists within the unit.</p><p>For example, say we wanted to measure time. Our unit would be duration, but we’ve got several ways to represent duration such as the second, minute and hour:</p><pre>let abstractValue = 1.0</pre><pre>// 1 second<br>let seconds = Measurement(value: abstractValue, unit: UnitDuration.seconds)</pre><pre>// 1 minute<br>let minutes = Measurement(value: abstractValue, unit: UnitDuration.minutes)</pre><pre>// 1 hour<br>let hours = Measurement(value: abstractValue, unit: UnitDuration.hours)</pre><p>Foundation includes a truckload of dimensional units, everything from electrical currents to pressure. Though you are free to subclass and create your own units, in fact — there is quite robust support for that, I’m not sure you’ll ever need to.</p><p>Here are some common dimensional units baked in for free:</p><ul><li>UnitLength : Base Unit is meters (m)</li><li>UnitMass : Base unit is kilograms (kg)</li><li>UnitDuration : Base unit is seconds (sec)</li><li>UnitArea : Base unit is square meters (m²)</li><li>UnitAcceleration : Base unit is meters per second squared (m/s²)</li></ul><p>There are about 170 dimensional unit types and it’s likely Foundation has thought of your use case.</p><h4>Operating on Measurements</h4><p>Working with measurements is trivial due to the fact that they conform to equatable out of the box, so comparisons are carried out uniformly:</p><pre>let abstractValue = 1.0</pre><pre>let seconds = Measurement(value: abstractValue, unit: UnitDuration.seconds)<br>let minutes = Measurement(value: abstractValue, unit: UnitDuration.minutes)</pre><pre>// 61.0 seconds, measured in the dimension&#39;s base unit<br>let totalTime = seconds + minutes</pre><pre>// 30.5 seconds<br>let halfTheTime = totalTime/2</pre><p>The entire measurement API does all of the heavy lifting for you. This is true when you operate on units of the same dimension but in different forms. The result of the operation will simply provide the base unit type:</p><pre>let imperialLength = Measurement(value: 5280.0, unit: UnitLength.feet)</pre><pre>let metricLength = Measurement(value: 0.62, unit: UnitLength.kilometers)</pre><pre>// 2229.344 meters<br>let totalLength = imperialLength + metricLength</pre><p>Extending the usefulness is NSUnitConverter, which is an abstract class that converts a unit to and from the base unit of its given dimension. For most cases, that’s going to be units that adhere to a linear equation or a scale factor. As such, UnitConverterLinear will be supplied:</p><pre>let imperialLength = Measurement(value: 5280.0, unit: UnitLength.feet)</pre><pre>let metricLength = Measurement(value: 0.62, unit: UnitLength.kilometers)</pre><pre>// 2229.344 meters<br>let totalLength = imperialLength + metricLength</pre><pre>// 1.385 miles<br>let justMiles = totalLength.converted(to: UnitLength.miles)</pre><p>Don’t worry about creating conversions that don’t relate to one another. These will produce build time errors due to each type’s conversion requiring its generic unit type:</p><pre>// Build error<br>let nonsense = totalLength.converted(to: UnitTemperature.celsius)</pre><h3>User Facing Values</h3><p>Making these values show up in your user interface is going to be quite familiar if you’ve ventured into NSNumberFormatter’s waters. Its close cousin, NSMeasurementFormatter, use is essentially identical.</p><p>This is quite ideal, as writing these types of strings on our own time would quickly become a chore.</p><pre>if (isCanada)<br>{<br>    // kilometers 👌<br>}<br>else if (isChinese)<br>{<br>    // Translate the unit 😐<br>}<br>else if (isArabic)<br>{<br>    // Translate the unit, number representation AND make it right to left 😱<br>}</pre><p>Of course, Foundation and friends nails it:</p><pre>let distance = Measurement(value:10, unit: UnitLength.miles)</pre><pre>let frenchDistance = MeasurementFormatter()<br>frenchDistance.locale = Locale(identifier: &quot;fr&quot;)</pre><pre>let chineseDistance = MeasurementFormatter()<br>chineseDistance.locale = Locale(identifier: &quot;zh&quot;)</pre><pre>let arabicDistance = MeasurementFormatter()<br>arabicDistance.locale = Locale(identifier: &quot;ar&quot;)</pre><pre>// 🇫🇷<strong> </strong>-&gt; 16,093 km<br>print(&quot;🇫🇷 -&gt; \(frenchDistance.string(from: distance))&quot;)</pre><pre>// 🇨🇳<strong> </strong>-&gt; 16.093公里<br>print(&quot;🇨🇳 -&gt; \(chineseDistance.string(from: distance))&quot;)</pre><pre>// 🇯🇴<strong> </strong>-&gt; ١٦٫٠٩٣<strong> كم</strong><br>print(&quot;🇯🇴 -&gt; \(arabicDistance.string(from: distance))&quot;)</pre><p>Since measurements tie in closely with numbers, it’s also possible to pair a measurement formatter with a number formatter to specify digits, for example:</p><pre>let distance = Measurement(value:0.2, unit: UnitLength.miles)</pre><pre>let frenchDistance = MeasurementFormatter()<br>frenchDistance.locale = Locale(identifier: &quot;fr&quot;)</pre><pre>// 🇫🇷<strong> </strong>-&gt; 0,322 km<br>print(&quot;🇫🇷 -&gt; \(frenchDistance.string(from: distance))&quot;)</pre><pre>let digitFormat = NumberFormatter()<br>digitFormat.minimumSignificantDigits = 4</pre><pre>frenchDistance.numberFormatter = digitFormat</pre><pre>// 🇫🇷<strong> </strong>-&gt; 0.321868 km<br>print(&quot;🇫🇷 -&gt; \(frenchDistance.string(from: distance))&quot;)</pre><p>There are several configurations that the measurement formatter affords to you. Be sure to glance over its <a href="https://developer.apple.com/documentation/foundation/measurementformatter">documentation</a>. Also note that the formatter will takes its default system locale when initialized, so it’s typically unnecessary to directly assign to its locale property as we’ve done here.</p><h4>Testing Locales — The .easy Way</h4><p>A quick foot note. Part of the magic of utilizing Foundation’s measurement and unit APIs is that they are locale aware. If you’re currently changing the location within the iOS simualtor to see how things shake out, there is another way you might prefer.</p><p>Just dupe your scheme, and pick the desired locale:</p><ul><li>Edit Scheme</li><li>Hit “Duplicate Scheme”, it’s in the bottom left in Xcode 9</li><li>Name it</li><li>Under Run -&gt; Options -&gt; Application Region, then choose the region to test with</li></ul><p>This is nice, because it’s a no fuss and deliberate approach. It requires no code changes or mucking around with the (always reliable 🤞) iOS simulator.</p><p>Additionally, you can use the same approach to test string localizations within your interface by editing the “Application Language” in the same manner you edited the region.</p><h4>Wrapping Up</h4><p>It wasn’t until I started working on an international team that I truly began to appreciate accurate measurements within iOS. Or — even the correct unit of measurement <em>period</em>.</p><p>While the rest of the world embraces the metric system, here I am sticking out like a sore thumb while communicating distances via the imperial system. Siri has a soul, and I know this because she is sick of answering how many miles equals 1 kilometer. I hear it in her cold, hard, digital voice when she answers it for 144th time for me 🤖.</p><p>Let’s all aspire to not be that app that delivers the wrong units, or incorrect measurements, in our own software. Foundation has us covered.</p><p>Until next time ✌️</p><p><a href="https://www.twitter.com/jordanmorgan10">Jordan Morgan (@JordanMorgan10) | Twitter</a></p><pre>If you enjoyed this week&#39;s post, please feel free to go ahead and NSRecommend(this, where: below);</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2be0d84bda64" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-traveled-ios-developers-guide/nsmeasurement-2be0d84bda64">NSMeasurement</a> was originally published in <a href="https://medium.com/the-traveled-ios-developers-guide">The Traveled iOS Developer’s Guide</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Copy on Write in iOS 11]]></title>
            <link>https://medium.com/the-traveled-ios-developers-guide/copy-on-write-in-ios-11-c4ad2a61c285?source=rss----79a4c0617ed4---4</link>
            <guid isPermaLink="false">https://medium.com/p/c4ad2a61c285</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Jordan Morgan]]></dc:creator>
            <pubDate>Tue, 07 Nov 2017 22:32:36 GMT</pubDate>
            <atom:updated>2018-12-19T22:44:42.280Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0SdFNRP8sH-LKEdSvZxXZg.jpeg" /><figcaption>How many great things were made from a coffee and a mac 🤔?</figcaption></figure><h4>Foundation Collections Get Snappier | Smarter | More Efficient</h4><blockquote>A quick note — all of my future posts will be published on my <a href="https://www.swiftjectivec.com/index.html">dedicated website</a> and this publication is no longer being updated. Thanks for reading!</blockquote><p>Foundation is the unsung hero of iOS development. Powerful due in part to its maturity and ubiquity — it boasts all of six major implementations, it treats engineers to everything from the basic object to annual optimizations under the hood at WWDC. And the best optimizations are the ones I don’t even have to make. They just happen.</p><p>With copy on write semantics for Foundation collections, this week’s topic, that’s exactly what we get.</p><h4>C.o.W Primer</h4><p>Both the amatuear and the veteran programmer know that we don’t go far without embracing collections, yet by and large there isn’t much thought or questioning that occurs as to what their doing behind the scenes or how exactly they work beyond our CompSci 101 course.</p><p>It can sometimes serve as intimidating subject matter, but luckily copy on write is both a simple concept and, as such, is easy to conceptualize. The elevator pitch is that instances pointing to the same object shouldn’t need to employ full copies unless one of them, does in fact, mutate:</p><pre>NSMutableArray *ar1 = [@[@&quot;TTIDG&quot;,@&quot;Pizza&quot;] mutableCopy];<br>NSMutableArray *ar2 = [ar1 mutableCopy];</pre><p>Here, both variables hold the same data. So why create a full copy unless it’s actually needed? This means that instead of creating the full copy, we can just utilize pointers to the same backing store and enjoy a much more efficient O(1) operation.</p><p>All we’re talking about here is an optimization strategy. Even better, the whole technique is all in the name. We shouldn’t copy data unless it’s written to, in which case — we have a reason to carry forward the actual copy. Copy on write.</p><p>So, TL;DR — copies are super cheap now. In fact, they are almost downright free for defensive copying code. In the past, they were typically linear at best.</p><h4>Foundation Implications</h4><p>This means that our good friends NSSet, NSDictionary and NSArray will all benefit from the optimization made by the folks maintaining the Foundation Framework. Going back to our previous example:</p><pre>NSArray *ar1 = @[@&quot;TTIDG&quot;,@&quot;Pizza&quot;];<br>NSMutableArray *ar2 = [ar1 mutableCopy];</pre><pre>// Currently, both arrays point to the same backing store</pre><pre><br>// Now a mutation occurred, with CoW - this is where the copy actually takes place<br>[ar1 removeLastItem];</pre><p>A large number of application flows might not ever reach a mutated state, thus the copy operation was effectively wasted effort. If it doesn’t occur, the only hit we’ll take with CoW is the allocation of the second collection — which likely won’t be much.</p><p>But — be mindful of what it isn’t:</p><pre>NSArray *ar1 = @[@&quot;TTIDG&quot;,@&quot;Pizza&quot;];<br>NSMutableArray *ar2 = ar1;</pre><p>This isn’t the same at all, and copy on write doesn’t apply. Here we’re pointing to the exact same reference in memory. Remember that this particular optimization is all about efficient copies. Even though pointing to a reference and copying data deals with sharing said data, they are much different in implentation.</p><h4>Applications</h4><p>Even though copy on write is a performance optimization, it shouldn’t soley be thought as one in pragmatic terms. It’s great that it’s there, we’ll benefit from it without having lifted a finger — but how we can leverage it to do things we maybe couldn’t before?</p><p><a href="https://developer.apple.com/videos/play/wwdc2017/244/">Session 244 at WWDC 17</a> offered a few great examples. Suppose we have an array property:</p><pre>@property (strong) NSArray *foo;</pre><p>The intention of the declaration implies that it shouldn’t have mutable state. But hey — life comes at you fast:</p><pre>// Trolling<br>self.foo = [NSMutableArray new];</pre><p>Now, consider this:</p><pre>@property (copy) NSArray *copiedArray;<br>@property (strong) NSArray *stongArray;</pre><pre>self.copiedArray = [NSMutableArray new];<br>self.strongArray = [NSMutableArray new];</pre><pre>// Logs out &#39;No&#39;<br>NSLog(@&quot;%@&quot;, [self.copiedArray isKindOfClass:[NSMutableArray class]] ? @&quot;Yes&quot; : @&quot;No&quot;);</pre><pre>// Logs out &#39;Yes&#39;<br>NSLog(@&quot;%@&quot;, [self.strongArray isKindOfClass:[NSMutableArray class]] ? @&quot;Yes&quot; : @&quot;No&quot;);</pre><p>The copy attribute has been around since the beginning — and it’s commonly put to great use with class clusters. What’s happening here is that sending a copy message to something that is mutable (i.e. the NSMutableArray here) will still return an immutable copy. Copy on write makes life even faster in such a scenario.</p><p>Continuing on with Objective-Cisms — mutable collections are often used to build something up. This is a common technique found within many functions, where the author will then declare the return type as immutable. Yet, since a mutable array is a kind of array, this is perfectly legal:</p><pre>- (NSArray &lt;Employee *&gt; *)allEmployees {<br>    NSMutableArray *container = [NSMutableArray new];</pre><pre>    //build up container with employees...<br>    //i.e. [container addObject:anEmployee]</pre><pre>    return container;<br>}</pre><p>And innocently enough, we’ve sharing mutable state again. The method header deceives any caller now, the 🍰 is a lie.</p><p>Since we’ve got copy on write, we don’t even need to bother with such a qundary since copies are cheap. We can do the right thing and sleep easy on performance hits:</p><pre>- (NSArray &lt;Employee *&gt; *)allEmployees {<br>    NSMutableArray *container = [NSMutableArray new];</pre><pre>    //build up container with employees...<br>    //i.e. [container addObject:anEmployee]</pre><pre>    return [container copy];<br>}</pre><p>Also — Swift 👋?</p><p>Think about the bridging process. If you, or perhaps another framework, have a foundation collection returned to you that one has to use in Swift code — you’re getting the value type of the collection since the language employs value type semantics.</p><p>How does one enforce that 🤔?</p><p>…with a copy on the reference type during the bridging process. So now if that bridged data was never mutated, the whole bridging operation’s efficiency is greatly improved. Which, I suppose, is a nice seque to wrap things up.</p><h4>Final Thoughts</h4><p>As I positied in one of <a href="https://medium.com/the-traveled-ios-developers-guide/objective-c-in-2015-3cb7dab3690c">my more popular articles a few years ago</a>, Objective-C has become stronger and more capable due to Swift’s presence alone. The sea of apps using Objective-C runs deep, and now their collections run faster. It’s not surprising, as copy on write semantics have been with Swift developers since the beginning.</p><p>And now, here we are, with Objective-C getting in on the fun now. #DinosaurNotDead, am I right?</p><p>Until next time ✌️</p><p><a href="https://www.twitter.com/jordanmorgan10">Jordan Morgan (@JordanMorgan10) | Twitter</a></p><pre>If you enjoyed this week&#39;s post, please feel free to go ahead and NSRecommend(this, where: below);</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c4ad2a61c285" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-traveled-ios-developers-guide/copy-on-write-in-ios-11-c4ad2a61c285">Copy on Write in iOS 11</a> was originally published in <a href="https://medium.com/the-traveled-ios-developers-guide">The Traveled iOS Developer’s Guide</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[iOS 11: The DeviceCheck API]]></title>
            <link>https://medium.com/the-traveled-ios-developers-guide/devicecheck-6f3eafac60e5?source=rss----79a4c0617ed4---4</link>
            <guid isPermaLink="false">https://medium.com/p/6f3eafac60e5</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Jordan Morgan]]></dc:creator>
            <pubDate>Fri, 06 Oct 2017 19:55:48 GMT</pubDate>
            <atom:updated>2019-01-25T16:31:57.438Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MMwOs-jKbVsDt-IrNnIgew.jpeg" /><figcaption>In honor of national coffee day last week, I present a coffee shop stock photo ☕️</figcaption></figure><h4>Like Creeping, Just Legally</h4><blockquote>A quick note — all of my future posts will be published on my <a href="https://www.swiftjectivec.com/index.html">dedicated website</a> and this publication is no longer being updated. Thanks for reading!</blockquote><p>Each WWDC, there is always the obscure API that finds its way into the annual “word bubble” slide of new toys for developers to use. Faintly sitting there, it stands to reason that Apple considers it a useful addition that only the few, and not the many, will use.</p><p>DeviceCheck fits that bill, and then some. You might consider it a necessity from Cupertino &amp; Friends<strong>™</strong>, something they had to make or face the reality that engineers would find another way to do thing X or Y resulting in shady means to the same end. Because developers don’t do shady things, <a href="https://daringfireball.net/2017/04/uber_identifying_and_tagging_iphones">like ever</a>.</p><p>So, DeviceCheck is kinda what happens when most devs want to do things for perfectly valid business reasons, but there aren’t really any good ways to do it. It’s a curious little API, our topic of discussion this week.</p><h4>So, What Is It?</h4><p>The TL;DR is nothing more than this: It’s an Apple approved, and guaranteed way, to identify your app as running on a valid Apple device while maintaining absolute user privacy.</p><p>That’s not the most interesting of news, I suppose. The real discussion here lies within the <em>why</em> part of things. And the why spectrum, in this case, could range from toggling promotional offers on a certain device, linking purchases to accounts or auditing a device for fraudulent activity. For example, who here in the room has made two different usernames or profiles to extend a free trial of some sort?</p><p>…</p><p>…..</p><p>……..</p><p>🙋🏻‍♂️.</p><p>That’s really it. We’re simply taking about helping one associate some given state for any given iOS (or tvOS) device in particular.</p><p>To get your creative juices flowing, consider that you have two apps released. If they open App One, you could assign the device to state 01 — and when they open App Two, you can query the state as it will be persisted in the same fashion and then unlock some content, discount or reward.</p><p>It’s an app-agnostic API, so leverage it as such if the occasion calls for it. But, also be aware if that presents a design constraint to you. Again, we’re talking about two bits <em>per device</em> — not two bits per app.</p><p>So — how does it work?</p><h4>The API</h4><p><a href="https://medium.com/the-traveled-ios-developers-guide/ios-11-privacy-and-single-sign-on-6291687a2ccc">I’ve always appreciated “just get to the point” type of APIs</a>, and that’s exactly what we get here. The setup allows a developer to store two bits of information (along with a timestamp) per one device. So, instead of peeking behind several doors that Apple would rather you leave shut to identify a device, you can simply get a few bits back and be done with it:</p><pre>let curDevice = DCDevice.current</pre><pre>if curDevice.isSupported<br>{<br>    curDevice.generateToken(completionHandler: { (data, error) in<br>        if let tokenData = data<br>        {<br>            print(&quot;Received token \(tokenData)&quot;)<br>        }<br>        else<br>        {<br>            print(&quot;Hit error: \(error!.localizedDescription)&quot;)<br>        }<br>    })<br>}</pre><blockquote>Note that the simulator won’t pass isSupported, so if you want to test it out— I guess do what we should be doing anyways and use the real thing 📱.</blockquote><p>With that code you’re on your first step (more to follow) to be able to store either:</p><ul><li>00</li><li>01</li><li>10</li><li>11</li></ul><p>When you set that information, it remains valid and stored by Apple until you as the developer manually reset it or until you update it. That means you don’t have to code your way through tricky things like reinstallation, nuking all contents and settings or straight up deletion. It’s also worth noting that these values are unique per team ID.</p><p>Also, be aware that like most tokens, it’s intended for single use. As you’ll see in just a minute, you likely use this token outside of your app and on your server. It will stay valid long enough if you need to retry a request, but the big Apple just recommends invoking the same method to generate another one.</p><h4>A Closer Look</h4><p>You may be looking at the previous code sample and wondering how that really helps us at all. How are the bits assigned? How do you set state? All we’re doing so far is getting a token. You might’ve expected something like this:</p><pre>let curDevice = DCDevice.current<br>curDevice.setFirstBitState(as: true)</pre><pre>// or</pre><pre>if curDevice.secondBitState() == true<br>{<br>    // Do something<br>}</pre><p>It’s a fair question, and it’s because the client API (iOS or tvOS) only handles half of the transaction. On iOS, we’re given an ephemeral token which we send to our own servers. That validates authenticity, then we can either set the bit state or query it and fire a request off to Apple. Then Apple gives us the state we’re after.</p><p>It looks like this:</p><ol><li>Client uses DeviceCheck to get a token</li><li>It sends that over to our servers and we decide state</li><li>We pass the token and state to Apple, and done</li></ol><p>And then to query it later:</p><ol><li>Client uses DeviceCheck to get a token</li><li>Your server queries the state of the device with Apple</li><li>It gets the response and your app takes the appropriate action</li></ol><p>This is not as heavy handed as it sounds. A simple POST and wrapping up your authentication key as a JSON Web Token gets you all the way there. A request to query bit state would just need to include a JSON payload like this:</p><pre>{<br>   &quot;device_token&quot; : &quot;anAmazingUniqueToken&quot;<br>   &quot;timestamp&quot; : 0934423486434,<br>   &quot;transaction_id&quot; : &quot;you come up with this&quot; <br>}</pre><p>And then Apple would respond with:</p><pre>{<br>   &quot;bit0&quot; : false<br>   &quot;bit1&quot; : true,<br>   &quot;last_update_time&quot; : &quot;2017-10&quot; <br>}</pre><p>Coming back the other way, if one needs to update it - the payload is exactly the same except you include one, or both, of the bits you wish to update:</p><pre>{<br>   &quot;device_token&quot; : &quot;anAmazingUniqueToken&quot;<br>   &quot;transaction_id&quot; : &quot;you come up with this&quot;,<br>   &quot;timestamp&quot; : 0934423486434,<br>   &quot;bit0&quot; : false,<br>   &quot;bit1&quot; : true<br>}</pre><p>In saying all of this, I assume you are aware of the other logistical trappings one must take to send web requests. For example, follow the Base 64 URL encoded JSON web token format and ensure that your authentication key employs the ES256 algorithm. Otherwise, you’ll be met with no helpful bits to use for state and instead get a nice BAD_AUTHENTICATION_TOKEN http error 🙈.</p><p>For more on how to set these requests up, what data types to use and even some example requests using curl — <a href="https://developer.apple.com/documentation/devicecheck/accessing_and_modifying_per_device_data">be sure to hit the docs</a>.</p><h4>Being a Good DeviceCheck Citizen</h4><p>As with any API, there are right and wrong ways to go about things. With DeviceCheck, simple though it may seem, there are a few choice scenarios to be cognizant of.</p><p>For starters, recall that time stamp that Apple gives us during our query:</p><pre>{<br>   &quot;bit0&quot; : false<br>   &quot;bit1&quot; : true,<br>   &quot;last_update_time&quot; : &quot;2017-10&quot; <br>}</pre><p>That update time is rounded to the nearest month. This could help you solve some problems that could arise from things like devices being sold to someone else. For example, if the bit state says they’ve done something they should only do once, but it’s been a year since they’ve tried that — pair that fact with other business logic to avoid locking a new customer away from content.</p><p>That directly leads us to the next tip Apple recommends, which is that this is a <em>supplementary</em> source to help solve these specific problems. That is, it should be paired with your business logic. Getting the bit state is a great start and certainly welcome help, but pair it with logical checks that help you ensure you’re not stonewalling new users.</p><p>It’s also mentioned that this shouldn’t affect your user interface much. I think this is fairly obvious, but an additional nudge never hurts. Most of us have several ways of knowing when to toss up your “first run” modal that introduces your app. Querying a bit state that requires at least three trips across the wire shouldn’t be one.</p><p>Lastly, Apple gave us this API for a reason. In the <a href="https://developer.apple.com/videos/play/wwdc2017/702/?time=1530">WWDC chat</a> over the topic, they straight up say that they will continue to remove sources of entropy outright or at least make sure they are under user control. Read: “If you abuse our ecosystem to tag phones we will find you and eliminate your methods.”</p><h4>Wrapping Up</h4><p>UDID querying is out. Linking back via an IP address is hacky and easily dodged. So now the act of uniquely identifying an iOS device, nefarious reasons or not, has first class support in iOS 11. I, for one, applaud Apple’s decision to include a safe and pragmatic way to do this. Because somewhere out there is a dev with a business requirement that needs to do something like this.</p><p>Now, they can. And they don’t have to do any funky dances to do it.</p><p>Until next time ✌️.</p><p><a href="https://www.twitter.com/jordanmorgan10">Jordan Morgan (@JordanMorgan10) | Twitter</a></p><pre>If you enjoyed this week&#39;s post, please feel free to go ahead and NSRecommend(this, where: below);</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6f3eafac60e5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-traveled-ios-developers-guide/devicecheck-6f3eafac60e5">iOS 11: The DeviceCheck API</a> was originally published in <a href="https://medium.com/the-traveled-ios-developers-guide">The Traveled iOS Developer’s Guide</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>