<?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[Stories by Mike Sand on Medium]]></title>
        <description><![CDATA[Stories by Mike Sand on Medium]]></description>
        <link>https://medium.com/@mikesand?source=rss-b277a2123ef------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*ZYXF4HfKY4VtQbSsIAKfZg.jpeg</url>
            <title>Stories by Mike Sand on Medium</title>
            <link>https://medium.com/@mikesand?source=rss-b277a2123ef------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 14 Jul 2026 01:13:22 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@mikesand/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Apple Developer Documentation’s Simple, Fundamental Design Flaw]]></title>
            <link>https://medium.com/@mikesand/apple-developer-documentations-simple-fundamental-design-flaw-afcc6585775?source=rss-b277a2123ef------2</link>
            <guid isPermaLink="false">https://medium.com/p/afcc6585775</guid>
            <category><![CDATA[navigation]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[apple-development]]></category>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[documentation]]></category>
            <dc:creator><![CDATA[Mike Sand]]></dc:creator>
            <pubDate>Sun, 09 Jan 2022 22:39:33 GMT</pubDate>
            <atom:updated>2022-01-09T22:39:33.768Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Not every hierarchy is a navigation hierarchy</em></p><p>For anyone developing for Apple’s platforms, Apple Developer Documentation is a essential resource. On the web at <a href="https://developer.apple.com">https://developer.apple.com</a>, it’s one of the few places to get detailed authoritative information about Apple platforms.</p><p>Unfortunately, information on most Apple Developer pages is harder to understand than it needs to be because of a simple misconception apparent in the design of the pages.</p><p>(Full disclosure: I applied to work on the Apple Developer Documentation team in 2017, had a positive experience, and was invited to reapply later or apply to another team, but did not because I did not want to relocate.)</p><p>An example illustrates this clearly. Landing on <a href="https://developer.apple.com/documentation/arkit/arsession/3214028-identifier">this page</a> on iPhone:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cc8IaMxKgikNXEnTpd7qaQ.jpeg" /><figcaption>The page for `identifier` on iPhone.</figcaption></figure><p>Identifier for what? What session?</p><p>When there is more screen space, as on iPad, the results are a little better:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WWgZa7FQpJ1PFGwMn8E8aw.jpeg" /><figcaption>The page for `identifier` on iPad.</figcaption></figure><p>By looking in the navigation bar, and noticing the third of four items that is the immediate parent of this page, we can see that we are in fact looking at an instance property of ARSession, the fundamental starting point of Apple platform AR experiences.</p><blockquote>Saying “identifier is an instance property” is incomplete, equivalent to saying “identifier is an instance property on”. Instance property <strong>on</strong> what? It’s an incomplete statement.</blockquote><p>This is the flaw: Each page is designed as if it completely independent, and the parent is of no relevance other than as the source of the navigation.</p><p>If there is any doubt, inspecting the element on desktop confirms that the navigation bar that embeds ARSession has the aria accessibility tag “Breadcrumbs”:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*o5DKKTMy7GZ1b9nQGzjDjw.png" /><figcaption>The type that the instance method</figcaption></figure><p>The misconception is not the fault of ‘the designers’. The documentation is organized in a single unified hierarchy; the pages have designed with best practices for a website organized in a hierarchy. And the unified hierarchical organization of developer.apple.com is good, actually: good for navigation and good for general organization of a massive complex topic.</p><p>This is why the page becomes even less intelligible on iPhone: Breadcrumbs are the first thing to be sacrificed, as it’s a safe assumption this not important information. On pages that describe aspects of objects in object-oriented programming, this is a fundamental mistake.</p><p>To look closer and at possible low-impact solutions, it’s necessary to look at the what this concepts being presented actually are.</p><h3>Object-Oriented Programming: State and Behavior</h3><p>Object-oriented programming remains fundimental to development for Apple platforms and everywhere and not just for legacy reasons. One key reason is that object-oriented programming helps make programs easier to reason about — managing complexity being a fundamental skill of software development.</p><p>What is an “object” in object-oriented programming? One definition perfect for us is <em>an object encapsulates state and behavior</em>.</p><p>“State and Behavior” maps to the categorizations of identifier above: <em>state</em> is encapsulated in <em>Instance Properties </em>and <em>Class Properties, </em>and<em> behavior </em>is<em> </em>encapsulated in <em>Instance Methods </em>and <em>Class Methods</em>.</p><p>What is “encapsulated”? It means, among other things, that these properties and methods are defined in terms of the class, or object. They have no “global” meaning. They only have meaning as part of the object they are in.</p><p>Another analogy would be <em>transitive</em> verbs in English grammar. A <a href="https://www.grammarly.com/blog/transitive-and-intransitive-verbs/">transitive verb</a> requires a direct object to be grammatically correct. Conversely, an intensive verb does not and can stand alone: <em>I am going to shop [period], </em>with shop being intransitive. A transitive verb requires a direct object to receive the meaning: <em>I am going to buy [period]</em> is grammatically incorrect if there is no direct object in the sentence specifying what the speaker is going to buy.</p><p><em>Instance Methods</em> and <em>Instance Properties</em>, and <em>Class Methods</em> and <em>Class Properties</em>, make no programmatic sense outside of the type — why the page for ARSession.identifier is unintelligible.</p><h3>Solution: Seeing in Context</h3><p>On iPhone or other compact size classes, as seen in the first image above, currently the type is not even visible without tapping the dropdown “Documentation.” A simple stopgap solution is evident. Pages in the instance/class object-oriented categories could show the parent of the current page. While a deviation from general principles of navigation, the immediate benefits of seeing the type <em>that the page is in fact about </em>will make these pages dramatically easier to understand.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3av7LRlTMFzykHbncsYwNQ.png" /><figcaption>The first image, modified so the nav bar shows the parent of the instance property’s page instead of the root.</figcaption></figure><p>In the long term, documentation teams need to work with designers to find a way to identify how to present all of the necessary context on each page for each symbol. If the symbol is a instance method or class method or instance property or class, it’s essential for the type to be displayed prominently.</p><p>There are more possibilities for embedding domain knowledge into the navigation and presentation. For example, the Vision framework uses a multi-level series of subclasses on the base VNRequest and VNObservation to specialize vision capabilities, an appropriate design choice for functionality that is is specialized additively: Subclasses add new functionality but retain superclass’s methods and properties, which remain essential.</p><p>Currently, though, to try to understand a Vision subclass requires keeping multiple pages open and manually reconciling them, as well as reading superclasses while trying to keep track of . Embedding superclass methods in the child page, either with specialized notes or just as a reduncdency, would make Vision Request and Observation specialized task pages more complete and easier to understand.</p><p>Regardless, developer.apple.com needs to ensure. The site is essential, and is generally fast, complete and good looking. Web sites remain the best way of presenting these vast libraries of information. With the slightest tweaks, surely the result of misconceptions rather than intentional, the ability of Apple to communicate to platform developers will be even more effective.</p><p><em>Mike Sanderson is an iOS developer in Brooklyn, NY.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=afcc6585775" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[An Open Message to Forrester Research: What is a model to follow?]]></title>
            <link>https://medium.com/@mikesand/an-open-message-to-forrester-research-what-is-a-model-to-follow-9512facaff03?source=rss-b277a2123ef------2</link>
            <guid isPermaLink="false">https://medium.com/p/9512facaff03</guid>
            <category><![CDATA[powertofly]]></category>
            <category><![CDATA[nlrb]]></category>
            <category><![CDATA[workplace-bullying]]></category>
            <category><![CDATA[hr]]></category>
            <category><![CDATA[forrester-research]]></category>
            <dc:creator><![CDATA[Mike Sand]]></dc:creator>
            <pubDate>Mon, 25 Oct 2021 18:13:02 GMT</pubDate>
            <atom:updated>2021-10-25T18:13:02.741Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Paralanguage</em> usually refers to the nonverbal components of speech, as put in <em>Language Culture and Society: An Introduction to Linguistic Anthropology</em>, “noticeable variations in pitch, tempo, rhythm, articulation, or intensity” (Salzmann 2004: 247).</p><p>When I taught English as a Foreign Language in China, the best example of paralanguage I had was “Are you coming today or tomorrow?”. Inherently ambiguous in writing, the question was usually not ambiguous when spoken: It could be pronounced “Are you coming <em>today </em>or <em>tomorrow?</em>”, (<em>today⬆ </em>or<em> tomorrow⬇?) </em>expecting arrival in the next two days;<em> </em>or “Are you coming <em>today or tomorrow</em>?”, the entire sentence asking a yes-no question if arriving in the next two days (<em>today or tomorrow⬆</em>?).</p><p>Another example of ambiguity and paralanguage is the second clause in the title of this post, more a question of emphasis: It could be pronounced asking about specifically <em>what</em> is the referent of <em>a model</em>; or asking in a more general sense about the quote, “a model to follow”, that is deployed across marketing channels by Work &amp; Co marketing to imply Forrester Research’s endorsement. Two pronunciations:</p><ul><li><em>What</em> is a model to follow?</li><li>What is ‘a model to follow’?</li></ul><p>This message asks both questions.</p><p>To give background, my former employer, Work &amp; Co, has been under federal investigation by the NLRB since September 14. Work &amp; Co is under federal investigation specifically for violations of the NLRA for firing me for trying to discuss the abusive and corrupt HR process Work &amp; Co subjected me to in my last 5 months from March to August 2021. The full write up will be longer than a post, which is why I am first drawing out specific issues to focus on from the Work &amp; Co corruption:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*j3aJZ3_YXAzlMtAW3qCmgA.png" /></figure><p>The first question is “<em>What</em> is a model to follow?”. On the page, “Process”, it is folowed by the quote “We ask our clients to participate directly with us in an intensely collaborative process based on specific KPIs, rapid prototyping, and continuous testing and improvement.” However, I think I recall first seeing “a model to follow” specificaly attached to Work &amp; Co’s practice of not using timesheets, unusually for an agency. Since hourly timesheets are widely despised and mostly useless anyway, tracking work by the day is great, doing it at the resourcing level will usually make sense, and I can endorse that.</p><p>However, my view of the lack of timesheets did change as my situation at Work &amp; Co deteriorated, in response to months of bullying. I do think it contributed to upper management’s belief that “quality and speed of work” was subjective, not objective, and I had to accept whatever they decided to declare about my code despite my contention the “quality and speed of work” could in fact be objectively measured.</p><p>(In fact, when I was first asked to leave the project and company on June 22, the Director of HR said “Quality and speed of your work”, but on July 26, Aug 4, Aug 13, her phrase changed to “quality of work”. I had to correct her every subsequent time: “and speed?” I asked. “And speed” she affirmed. My current guess is while she was confident that lawyers would treat my code as hieroglyphics, the project managers would have to weigh in on “and speed” and they declined, for among other reasons, everything was tracked in the project management system.)</p><p>The second question of “What is ‘a model to follow’” is more utilitarian — stepping back, what is this quote for? I’d been seeing it across Work &amp; Co for years, and I saw it again on the page on <a href="https://powertofly.com">PowerToFly</a> when I became aware of that effort to open a pipeline of new marginalized people to replace the marginalized employees they have bullied, fired and alienated.</p><p>PowerToFly, which I was not familiar with, says “Our Mission Is: Connecting Diverse Talent To Big Career Moves” and on their <a href="https://powertofly.com/about">about</a> page, “empowering underrepresented talent”.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FLDC_wEp09ARyZ0P3XlVJg.png" /><figcaption>Work &amp; Co’s page on PowerToFly. PowerToFly says its “empowering underrepresented talent” and I am asking if the body text does that, or if it misleads underrepresented people, who will not be safe at Work &amp; Co — nor would anyone really be safe there, since Work &amp; Co HR subordinates engineering to favoritism and bullying</figcaption></figure><p><a href="https://medium.com/@mikesand/an-open-letter-to-powertofly-i-have-questions-25d9c4bdbc0b">I posted my questions for PowerToFly on Friday</a>. I am appending another question to PowerToFly:</p><ul><li>What are the standards for text in this box? Is this body text just a empty box where companies that have paid the fee to become a partner are allowed to write whatever they want? Is recruitment just another form of sales — all’s fair in recruitment and marketing?</li></ul><p>If this quote, “a model to follow”, is about timesheets and client process, why is it suitable for inclusion on . Of course companies can pump themselves up; and it was that Work &amp; Co has the top 0.1% designers and gets the biggest, splashiest contracts that I was happy doing the engineering for the iOS apps, as I have done successfully for 8 1/2 years now. And as I said Friday, Oct 22, I doubt PowerToFly would be set up to detect this and the company</p><p>But if PowerToFly’s mission is to empower marginalized people — and Work &amp; Co is a “partner” — I don’t think it’s appropriate to allow . And I think Forrester Research, if it does mean it’s an independent research company, should look. If nothing else, the federal investigation is advancing, facts are sworn in my affidavit, and Work and Co has submitted their response — apparently bog-standard defenses to violations of the NLRA Section 8(a)(1), that I was so terrible and not one other person cared about my problems, etc.,</p><p>PowerToFly should look at what they are letting Work &amp; Co say and imply, if they want to stay true to their mission and not send more marginalized people into the maw — where the Director of HR controls not just ordinary HR, but also the harassment complaint process, as complaints are sent directly to her email, and also receives a copy of anything sent into Work &amp; Co’s annoymous feedback form. This is not a safe place for marginalized people.</p><p>And Forrester Research doubtless would want to look at where their years-old quote is being deployed. Right now it seems to suggest that if marginalized people are looking for a place they can do their work free of harassment and bullying, Work &amp; Co is “a model to follow”. I suggest with what is still to come out, this is not a good look for an independent research company with a reputation to uphold.</p><p>Teaching paralanguage in China was so fun. Because Chinese students are drilled in tonal pronunciation as part of learning standard Mandarin, my Chinese students of English would be able to reproduce emphasis of pitch almost immediately, and they could themselves hear how immediately it improved their pronunciations. They would ask me, “if this is so important, why don’t we get taught this, often, from the beginning?”</p><p>It’s a good question, and my explanation was: “Because it’s unconscious”. Native speakers don’t think about it, it comes naturally, and that’s why it doesn’t get brought up enough — I agree it doesn’t — in the EFL books and lessons because — we just don’t think about it.</p><p>It recalls another offhand comment about paralanguage, from the person who taught me both linguistic anthropology and also investigative journalism: “You can use this as a lie detector.”</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9512facaff03" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[An Open Letter to “PowerToFly”: I have questions]]></title>
            <link>https://medium.com/@mikesand/an-open-letter-to-powertofly-i-have-questions-25d9c4bdbc0b?source=rss-b277a2123ef------2</link>
            <guid isPermaLink="false">https://medium.com/p/25d9c4bdbc0b</guid>
            <category><![CDATA[nlrb]]></category>
            <category><![CDATA[human-resources]]></category>
            <category><![CDATA[hr]]></category>
            <category><![CDATA[brooklyn]]></category>
            <category><![CDATA[workplace-bullying]]></category>
            <dc:creator><![CDATA[Mike Sand]]></dc:creator>
            <pubDate>Fri, 22 Oct 2021 18:42:22 GMT</pubDate>
            <atom:updated>2021-10-22T18:42:22.173Z</atom:updated>
            <content:encoded><![CDATA[<p>What is PowerToFly? I’m asking because I learned of PowerToFly’s existence through your mention of my former employer:</p><p><a href="https://www.linkedin.com/posts/powertofly_were-thrilled-to-announce-our-newest-partner-activity-6854066192001454080-3i-3">PowerToFly on LinkedIn: We&#39;re thrilled to announce our newest partner Work &amp; Co and welcome</a></p><p>I can only assume this is related to recent events inside Work &amp; Co, which displayed to everyone, starkly, how Work &amp; Co upper management actually deals with their marginalized employees who don’t know their place — why since September 14, Work &amp; Co is under federal investigation:</p><figure><img alt="Copy of NLRB charge" src="https://cdn-images-1.medium.com/max/1024/1*Co1JU78g7AucI8PNC_9-7w.png" /><figcaption>Charges identified by the NLRB Brooklyn office (Region 29) based on facts I provided</figcaption></figure><p>The NLRB is only investigating this final weeks of Work &amp; Co’s cover up, when on Aug 20 I posted first vaguely and then on Aug 27 posted substantively with documents and video in an open Slack channel, and asked to have a public discussion about how I had been treated over the past weeks and months.</p><p>At Work &amp; Co, marginalized people who try to bring allegations of mistreatment for a public internal discussion and said are instantly scolded, as I was on Aug 20; marginalized people who try to substantiate their claims are fired, as I was on Aug 27.</p><p>Both under the guise of rules against “calling out”. Is a policy against “calling out” the new legal way to smear and punish marginalized people who make unwelcome allegations, however substantiated?</p><p>As someone who is, to put it quickly, not gender confirming and not neurotypical, I would hope that if you do ask your new partner about this case, PowerToFly would not accept vague handwaving about my mental state, with statements about alleged respect for my privacy allowed to dodge questions about abuse and let loose with innuendo.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*O02FJob7CDZBSqiKrKaesg.png" /><figcaption>For the record, no one has ever apologized for the typo in the line obstensibly congradulating me for coming out as nonbinary. For the record, there was not a lot going on right then; my mental state was affected because I was being subjected to an abusive and corrupt HR process.</figcaption></figure><p>Another way to put this to PowerToFly, re: Work &amp; Co, is: Do you know where you are directing marginalized people? Do you know why?</p><p>I do not expect PowerToFly to verify my claims. But since you have proudly announced Work &amp; Co is your partner, and now advertising that you want to send more marginalized people to replace the employees they have alienated and fired, I have questions.</p><ul><li>Does PowerToFly consider its partners’ policies for employee speech? Is a policy that does not allow “calling out” compatible with a safe environment for marginalized people? If such a policy against “calling our” is acceptable, is it acceptable to reply to an employees posts by invoking the policy to cut their mic on a substantive change, allowing the company to character their actions and the employee’s actions internally without any response?</li><li>Does PowerToFly consider its partner’ policies following accusations of abuse? If someone makes an allegation against a specific person in upper management, is it appropriate for a PowerToFly partner to continue to have that person deal with the person they made the allegation against? After my first post on Aug 20, I was sent another message from the Director of HR, as if nothing had happened; the next week, I was encouraged to again get on a private call with the abusive director of HR.</li><li>Does PowerToFly consider its partners’ policies on HR complaints or formal harassment complaints? In April 2021, I was asked to leave a project I had worked on in various forms for 18 months, including shipping on-time in June 2020, three months into the pandemic. I though the reason I had been given were not legitimate, and asked for an investigation under the company’s expansive harassment policy, — I had identified the lines “intimidate, belittle, humiliate” -- but to keep the temperature low, specifically not alleging protected class bias or asking for any action, just investigation. 4 months later it was still being stalled, and the preliminary answer I received in August was astonishing —just to start, I was told I couldn’t be harassment because there were concerns about the quality of my work. On Aug 17, after her abusive conduct had been caught on a Zoom recording, while still trying to get me to join another call with the seniormost tech partner, the Director of HR said in a Slack message she would get me the result in writing by the end of the week (coincidently after our next scheduled meeting, Aug 20) but she never did.</li></ul><p>These general questions are not questions that are usually asked — and I think need to be asked more often, or always.</p><p>Like many others who have been victims of abuse, I have turned to activism. Yes, I seek justice for myself against the abusers, and while I could walk away and find a new job — I would rather be making iPhone apps, as I did successfully for 8 and 1/2 years — I am determined to see this through because they were only partially successful, and I have documents and video.</p><p>I assume this is new information for PowerToFly. You probably didn’t assume it; either because you aren’t set up to detect this, and indeed, the Director of HR and others at Work &amp; Co can be very superficially charming. And at lower levels, there are innumerable brilliantly capable people there is was a pleasure to work with. But I would urge no one go to work there until the labor case is resolved and also until Work &amp; Co stops stonewalling about their absuive HR processes.</p><p>I had a successful 18 months, but in 2021 at Work &amp; Co’s I experienced <a href="https://www.natcom.org/sites/default/files/pages/NCA_Anti-Bullying_Resources_Lutgen-Sandvik-Fletcher.pdf">textbook workplace bullying</a>; I only reluctantly came to accept the disturbing conclusion there is a cluster of capital-B bad people connected to the top, who mask their contempt for marginalized people behind splashy diversity initiatives.</p><p>I want to try to help others from becoming victims — both at Work &amp; Co and in general. That has brought me to write this letter. I hope that you respond substantially, not in words but in actions. Because now you have been told, and sending more marginalized people into that place would be complicit in Work &amp; Co’s workplace bullying and abuse.</p><p>Mike Sand<br>October 22, 2021<br>Brooklyn, NY</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=25d9c4bdbc0b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[iPadOS and iOS for Mac]]></title>
            <link>https://medium.com/tendigi-insights/ipados-and-ios-for-mac-31ef36f465f6?source=rss-b277a2123ef------2</link>
            <guid isPermaLink="false">https://medium.com/p/31ef36f465f6</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[apple]]></category>
            <category><![CDATA[apps]]></category>
            <category><![CDATA[ipad-os]]></category>
            <dc:creator><![CDATA[Mike Sand]]></dc:creator>
            <pubDate>Tue, 11 Jun 2019 21:00:11 GMT</pubDate>
            <atom:updated>2019-06-11T21:00:11.266Z</atom:updated>
            <content:encoded><![CDATA[<h3>New approaches to building for Apple Platforms</h3><p>Apple announced changes at WWDC that will reshape how to think about building apps for Apple’s platforms. One surprising announcement was iPadOS , turning what was always a variation of was a surprise announcement of what is effectively a new platform.</p><p>iPadOS is a departure from the use of “universal” iOS apps for iPhone and iPad since the iPad’s introduction in 2010, when it ran iOS 3. Following hardware differences like support for Apple Pencil and the use of USB-C instead of lightning on the 2018 iPad Pro models, it shows that the iPad is looking at use cases that have no equivalent on iPhone.</p><p>iPadOS’s headline new feature was multi-window support. Now apps can run in multiple “windows”. These iPadOS windows can appear in different multitasking frames and will appear separately in the new version existing task switcher, which each window for the app getting its own placement. which is less like iPhone and more like MacOS’s feature to show all windows, called “expose”.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bS02WSUBjPGDTGiHyn43IQ.png" /><figcaption>iPadOS’s new task switcher shows all of an app’s open windows</figcaption></figure><p>iPad wasn’t even the only hardware platform to split from iOS at WWDC 2019. Apple Watch apps can now run independently from iPhone apps, and have gotten their own Watch App Store as a result. This has been the obvious goal for WatchOS since its creation in 2015. Apps can continue to use a “hosting” iOS app, but are no longer required to do so. The Watch itself still requires an iPhone.</p><p>A real question about naming is why “iOS” has not changed to “iPhoneOS” — which actually would be a change back, since it was originally “iPhoneOS” publicly from versions 2 to 4. The first version of iOS was iOS (5), changed from iPhoneOS in part because of the iPad, which ran all iPhone apps from the start.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/450/1*AxXAxLd5HmzuD3bFHruQUw.jpeg" /><figcaption>iPhoneOS was the original name of iOS, and iPhoneOS would fit now more than ever.</figcaption></figure><p>Using the iPhone to push apps to other platforms is a reason why iPadOS was a surprising move. Apple still wants to use the overwhelmingly popular iPhone to drive apps to other platforms, including iPad. For developers, iPadOS could have seemed like a burdensome a new platform to support. That concern was alleviated by the introduction of the already-teased feature in a change teased last year as “Marzipan”, now dubbed “Catalyst”.</p><h3><strong>Write once, check 3 boxes</strong></h3><p>iOS apps can now be built simultaneously for 3 platforms at once: iPhone, iPad and Mac. Apple promises this is as simple as a checkbox.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/866/1*myjlRUTkMT9U3af6UfEjNg.png" /></figure><p>Previously a codebase that wanted to use iOS code on the Mac would need to separate our platform-independent code into a framework, then re-integrate it into a “target” for iOS or Mac. For iPad, iOS code would have its own methods to determine if it was running on iPhone or iPad, which ranged from the crude (checking if the device is an iPad) to the elegant but difficult to reason about (the system concept of “size classes” was never popular with developers).</p><p>Now Apple promises that a single codebase can run on all three platforms. Features that are dependent on platform, such as the difference between touchscreen taps and mouse clicks, will either be handled by the framework, or handled inline with a minimum of code differences.</p><p>This explains why the introduction of a new platform to support got such little attention or concern from developers, since in practice it promises to be no more work than supporting a universal iPhone and iPad app today, and supporting a MacOS app promises to now fall into that category.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xEveXdRxeHV9R0aeSH3aIA.png" /><figcaption>The same Voice Memos app running on iPad and Mac</figcaption></figure><p>Despite “Catalyst”, some apps may find that the requirements to support features such as multiple windows don’t makes sense or would result in a poor user experience. These apps may find it more aligned with their goals to drop iPad support and focus only on iPhone. (Even with iPad’s new multi-window support, developer guidance notes not every app needs to have multiple windows.) But if a codebase does handle multiple windows, they’ll be able to use that code for its iPad and Mac apps. iOS apps for Mac also will require MacOS Catalina, which will be available in the fall.</p><h3>iOS for Mac in Practice</h3><p>How seamless supporting multiple platforms will be in practice has yet to be determined. Our early experiments were mixed.</p><p>In initial tests with one app that we maintain for a client, it compiled and ran without issue — after we refined the handling of its window. After that, the iPad app on Mac received mouse clicks as touches interchangeable, and its support for multiple screen sizes on iPad translated perfectly to support for multiple sizes of a single MacOS window, including during resizing.</p><p>We tried to run another iPad app we maintain on Mac, but it would not build on Mac at all. It used legacy OpenGL code, which was deprecated by Apple last year. (Despite being depreciated for good reasons, OpenGL is so widely used its remove is almost unthinkable. Its deprecation was barely mentioned at WWDC, which would not be expected if its removal was on the horizon.)</p><p>How we could remove only the OpenGL code and run a subset of the app on the Mac was not immediately apparent. But this particular iPad app was a highly-custom, exquisitely designed iPad experience, and it didn’t seem like it would make sense on the desktop. The question of how we could move this iPad app to the Mac technically was a less important questions than if it made any sense to do so.</p><p>With the changes announced at WWDC 2019, everyone involved in making apps for Apple platforms needs to take a renewed look at how they choose what platforms to support. And ask themselves why, and how; the answer to why and how the different platforms are supported is set to get new answers.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=31ef36f465f6" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tendigi-insights/ipados-and-ios-for-mac-31ef36f465f6">iPadOS and iOS for Mac</a> was originally published in <a href="https://medium.com/tendigi-insights">Tendigi</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Core Data in Swift 1: Creating a Pure Swift NSFetchedResultsControllerDelegate]]></title>
            <link>https://medium.com/@mikesand/core-data-in-swift-1-creating-a-pure-swift-nsfetchedresultscontrollerdelegate-c9350ff8ede3?source=rss-b277a2123ef------2</link>
            <guid isPermaLink="false">https://medium.com/p/c9350ff8ede3</guid>
            <category><![CDATA[cocoa]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[generic-programming]]></category>
            <category><![CDATA[core-data]]></category>
            <dc:creator><![CDATA[Mike Sand]]></dc:creator>
            <pubDate>Fri, 20 Oct 2017 22:08:16 GMT</pubDate>
            <atom:updated>2019-06-10T16:29:48.229Z</atom:updated>
            <content:encoded><![CDATA[<h3>Mocking Core Data: Introduction</h3><p>The path to using Core Data in Swift is less like highway and more like a perilous trail clinging to the side of a mountain.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YziEQnSrxY8GxGj6gBpfCA.jpeg" /><figcaption>The path to correct Core Data in Swift.</figcaption></figure><p>Like many Swift issues, however, the issue is not new dangers but existing unsafe practices being revealed. One appraoch is to simply re-create the unsafe practices, such as with implicitly-unwrapped optionals; another is to wrap everything in so many levels of `guard` and `if let` that control flow becomes hidden among unnessary branches.</p><p>Regardless, the deeper that Objective-C’s assumptions have been built into a framework, the harder it is to use in the radically different world of Swift. That can be true even when attempts have been made by the system to bridge the gap, such as adding a Objective-C Generic to the NSFetchedResultsController, with mixed results.</p><p>After <a href="https://medium.com/@mikesand/nsfetchedresultscontroller-does-not-want-to-be-mocked-42802c4b1dc9">crashing the compiler</a> another approach was called for.</p><h3>Adapting FetchedResultsControllerDelegate</h3><p>The possibilities for working with NSFetchedResultsController in Swift are limited, like many Cocoa delegates, by the requirements imposed by it: The delegate must be an NSObject, its methods must be Objective-C, and the callbacks can’t be generic.</p><p>The goal is to adapt the NSFetchedResultsControllerDelegate to hide its legacy Objective-C baggage. This can be done by wrapping NSFetchedResultsController in an adapter class, an adapter class that does meet the legacy requirements, and that passes new delegate callbacks out in pure Swift.</p><p>The first step is to recreate the delegate as a Swift protocol:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8cfc7a3243044bcc8710ba727d43002f/href">https://medium.com/media/8cfc7a3243044bcc8710ba727d43002f/href</a></iframe><p>The interface here matches the NSFetchedResultsControllerDelegate almost exactly (leaving out the extraneous controller(_:sectionIndexTitleForSectionName)). The associatedtype is named ResultType, and since it will be the NSFetchedResultsController’s ResultType, it has the NSFetchRequestResult constraint, but we’re not confusing the compiler by asking it to bridge the Objective-C to Swift generics.</p><p>Notice we do still use the NSFetchedResultsController: We’re not ready to refactor that out yet; the goal right now is to adapt the delegate. So we keep the NSFetchedResultsController and its related `NSFetchedRequestResult` and `NSFetchedResultsChangeType`.</p><h3>FetchedResultsControllerAdapter class</h3><p>Then it’s possible to build out the adapter:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/715bcdb4d9d4daa973db42af6311f951/href">https://medium.com/media/715bcdb4d9d4daa973db42af6311f951/href</a></iframe><p>Even without decoding the generics it’s strightforard what’s going on: The delegate messages from the NSFetchedResultsController get transformed and passed on to the FetchedResultsControllerDelegate instance. Every detail needs to be considered, however, line-by-line:</p><h4>Class Declaration and Properties</h4><p>The class delecration, like most with generics, may not be intiutive. It can be understood in roughly three parts:</p><p>1) class FetchedResultsControllerAdapter&lt;Delegate: FetchedResultsControllerAdapterDelegate&gt;</p><p>The FetchedResultsControllerAdapter has a single generic type, Delegate, which is an instance of FetchedResultsControllerAdapterDelegate we created earlier. The AdapterDelegate must be a generic on the type because, as most Swift developers have learned, it can only be used as a generic constraint because it has Self or associated type requirements. Throughout the class, we will refer to this as Delegate.</p><p>Since Delegate has a ResultType, we can refer to that as well, such as in the Fetched Results Controller property:</p><p>private(set) var fetchedRequestController : NSFetchedResultsController&lt;Delegate.ResultType&gt;</p><p>Which is all that’s necessary to ensure the NSFetchedResultsController and the Delegate’s ResultType match.</p><p>2) NSObject, NSFetchedResultsControllerDelegate</p><p>FetchedResultsControllerAdapter is an NSObject, the requirement of the NSFetchedResultsControllerDelegate, which this class conforms to.</p><p>3) where Delegate: AnyObject</p><p>This constraint exists for memory management. Delegates are a classic source of retain cycles. If this object a strong reference to its delegate, keeping it alive, and if the delegate keeps a strong reference to the adapter — which it almost definitely will — keeping <em>it</em> alive, then the two objects would never be deallocated.</p><p>The best way to handle this is to delclare the property weak: <br>weak var resultsDelegate : Delegate?</p><p>But this can only be done with reference types; value types have no reference count because they have no references.</p><p>There are other ways to prevent a retain cycle if making the delegate class-bound wasn’t possible. The delegate (referring to the client that holds a reference to the adapter) could explicitly nil out its instance of the adapter in its `deinit` method; or in the delegate could call the adapter to set its delegate to nil (though there’s no good reason why something other than the delegate would have a refernce to this class). This would be acceptible added complexity if needed; but it’s not needed yet, and for now we just need to have the delegate property be weak.</p><h4>Init</h4><p>Init’s goal is to ensure that the correct arrangement of delegates is set up — which is only mostly possible.</p><p>1) init(frc: NSFetchedResultsController&lt;Delegate.ResultType&gt;, resultsDelegate: Delegate?) { //...</p><p>The init method sets up this wrapper class predictably: In the first parameter, it takes an already-configured FetchedResultsController, keeping various Core Data responsibilities out of this class to keep it focuses. The property (abbreviated to frc) is private(set) to force clients to use the init method; it’s publically accessible so that clients can use it freely.</p><p>The second parameter is the generic Delegate. Any client can provide an instance of any class that conforms to the protocol and it will work. One way to think about it is that for every concrete class uses, the compiler will create a new version of this class, substituting the concrete class for every use of Delegate. This is how it avoids confusing the Objective-C callers.</p><p>2) self.frc = frc <br>self.resultsDelegate = resultsDelegate <br>super.init() <br>self.frc.delegate = self</p><p>The call to super.init() stands out. The dance of the superclass intializers has been a source of frustration for Swift developers, but the rules often make a great deal of sense: This class can’t be a delegate of another object if it doesn’t yet exist, which it doesn’t until it has called super.</p><p>This is also the reason why delegate is optional in the init method, and instead is a publically-settable optional variable, even though this class doesn’t have much purpose if it doesn’t have a delegate: If another class wants to initialize an FetchedResultsControllerDelegateAdapter as part of its initialization process, it will need to perform the same call to super before doing so, or at least finish setting its own properties, which may include this adapter. If the adapter required a delegate as part of initaliztion, it would badly hem in clients.</p><p>It’s for this same reason that the Adapter doesn’t call performFetch() itself, instead exposing a method. Delegate methods could start firing immeditely, before the delegate is set, or clients could not be ready for delegate callbacks until some future point. Since clients can access the controller themselves, this method is somewhat a glorified reminder that the step is necessary.</p><h4>Deleagte Callbacks</h4><p>The delegate callbacks are straightforward, passing methods almost straight through from the @objc to the Swift protocol delegate.</p><p>However, the @objc delegate methods don’t pass in typed FetchedResultsControllers; all are merely typed to NSFetchedRequestResult. The passed-in controller could be cast to the appropriate type, but since this class is only every going to have one NSFetchedResultsController, it’s just as simple to pass that. A problem could result if for some reason this class was set to be the delegate of a different NSFetchedResultsController, but there’s no reason to do that.</p><h4><strong>The Use Site</strong></h4><p>A side effect of the generics is that clients must create a FetchedResultsControllerAdapter in effect, typed to themselves:</p><p>class MyViewController: UIViewController, UIFetchedResultsControllerAdapterDelegate {</p><p>var fetchedResultsController = FetchedResultsControllerAdapter&lt;MyViewController&gt;</p><p>Which may appear odd, as it’s not immeidtely apparant what the relationship between FetchedResultsControllerAdapter and MyViewController. A technique for creating non-generic concrete classes can be used here:</p><p>class MyViewControllerFetchedResultsControllerAdapter : FetchedResultsControllerAdapter&lt;MyViewController&gt; {}</p><p>Although the added complexity may or may not be necessary purely for readability at the site of use.</p><p>The approach taken here has liberated FetchedResultsController from the legacy restrictions on its delegates. Moreover, this adapter class only needs to be written once and then forgotten about.</p><p>With this adaptation, the liberated FetchedResultsController can start to take advantage of Swift’s amazing features to become even more powerful.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c9350ff8ede3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[NSFetchedResultsController does not want to be mocked]]></title>
            <link>https://medium.com/@mikesand/nsfetchedresultscontroller-does-not-want-to-be-mocked-42802c4b1dc9?source=rss-b277a2123ef------2</link>
            <guid isPermaLink="false">https://medium.com/p/42802c4b1dc9</guid>
            <category><![CDATA[core-data]]></category>
            <category><![CDATA[generic-programming]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Mike Sand]]></dc:creator>
            <pubDate>Fri, 20 Oct 2017 19:57:07 GMT</pubDate>
            <atom:updated>2017-10-21T15:28:13.397Z</atom:updated>
            <content:encoded><![CDATA[<p>Or more specifically, NSFetchedResultsController’s Objective-C generics do not play nicely with Swift protocols’ associatedtype.</p><p>The idea behind “Engineering for Testing” is to write code not against the interface of concrete classes, but against protocols that have the same interface and the concrete classes conform to. For “real” builds, the real object is used; for testing, a mock or fake object can be substituted, allowing robust tests.</p><p>For a Core-Data–based app, this meant creating an ‘NSFetchedResultsControllerPrototol’ that we would code against. NSFetchedResultsController actaully has a generic class that it useses — its rull deleration is NSFetchedResultsController&lt;ResultType&gt; : NSObject where ResultType: NSFetchedRequestResult. This is perfect for us, because then we can use an associated type, and then substitute mocks for the object vended.</p><p>This approach produced no inline error when writing it out, and planning and development proceeded with the assumption this would work. When it came time to build, however, the result was different, evetually isolated:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7VOa8AEDgfXrqB7zBOlywg.png" /><figcaption>Achivement Unlocked: Crash the compiler.</figcaption></figure><p>A segmentation fault during compilation means to compiler itself has crashed. Unfortunately it’s a regular occurrence when working with generics, and there’s no option in the short term but to work around.</p><p>(But before that was a crashing mess of warnings, errors that had a tendency to look like emoji of how they make you feel: &#39;_&#39;, &lt;_&gt;, etc.)</p><p>Core iOS functionality is still native Objective-C, and even when it’s represented in Swift, don’t assume it’s going to work until after validating as close to your specific use case as possible. There are still possibilities for mocking Core Data, including robust mocking; subsequent posts will explore them.</p><p><em>Edit: Now filed as </em><a href="https://openradar.appspot.com/35110402"><em>Open Radar 35110402</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=42802c4b1dc9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Constants: Struct static lets or enums?]]></title>
            <link>https://medium.com/@mikesand/constants-struct-static-lets-or-enums-b8ca9a8b7326?source=rss-b277a2123ef------2</link>
            <guid isPermaLink="false">https://medium.com/p/b8ca9a8b7326</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Mike Sand]]></dc:creator>
            <pubDate>Tue, 03 Oct 2017 14:44:31 GMT</pubDate>
            <atom:updated>2017-10-03T14:44:31.011Z</atom:updated>
            <content:encoded><![CDATA[<p>Organizing constant values in code has been important since before Swift, but provides several ways.</p><p>The goals is to fins a way to organize, very readable, esaiy to use and maintain.</p><p>The first way that was suggested, ealy in Swift, is to use an enum with a raw value:</p><pre>enum StoryboardID : String {<br>    case main<br>    case profile<br>    case edit<br>}</pre><p>This usage was popular enough that for Strings, Swift 2 automaticly uses the case name as the raw value. The above is:</p><pre>let mainStoryboardID = StoryboardID.main.rawValue <br>// mainStoryboardID == &quot;main&quot;</pre><pre>// But: </pre><pre>enum SegueID {<br>    case toDetail<br>    case toSettings<br>    case toEdit = &quot;toEditVC&quot; // One case raw value specified<br>}</pre><p>However, one minor downside is that to work with the string, you are always going to have to access the `rawValue` property:</p><pre>let mainStoryboard = UIStoryboard(name: StoryboardID.main.rawvalue, bundle: nil)</pre><p>Enums come with some other details that could interfear, or at least distract, from their use of constants. For one thing, enums should be able to be used interchangibly.</p><p>In most cases when you want to use a constant, you want t create a specific constant, not “any one of this grouping of constants.” Is there a better way to specify this?</p><p>##Static Let</p><p>Static constants just add constants as static variables (or constants)</p><pre>struct StoryboardID {<br>    static let main = &quot;main&quot;<br>    static let profile = &quot;profile&quot;<br>    static let edit = &quot;edit&quot;<br>}</pre><p>You don’t get the enum’s automatic conversion of the case into the constant string, but other than that, this is more flexible and specific:</p><pre>let mainStoryboard = UIStoryboard(name: StoryboardID.main, bundle: nil)</pre><p>Enums are still useful for checks: Where you know you want one of several possibilities, and need to be able to check which one you have.</p><pre>guard let segueIDString = segue.identifier, segueID = SegueID(rawValue: segueIDString) else { fatalError(&quot;Unknown segue \(segue.identifier)&quot;) }</pre><pre>switch segueID {<br>    case toDetail: //...<br>    case toSettings: //...<br>    case toEdit: //...<br>}</pre><p>The ability to enure that every case if covered is `enum`’s great benefit, and usuing enums just to hold independent values isn’t a good use of them.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b8ca9a8b7326" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Use of KeyPaths in Swift 4]]></title>
            <link>https://medium.com/@mikesand/a-use-of-keypaths-in-swift-4-ab8390ded6d1?source=rss-b277a2123ef------2</link>
            <guid isPermaLink="false">https://medium.com/p/ab8390ded6d1</guid>
            <category><![CDATA[keypath]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Mike Sand]]></dc:creator>
            <pubDate>Mon, 21 Aug 2017 03:35:49 GMT</pubDate>
            <atom:updated>2017-09-09T00:11:39.347Z</atom:updated>
            <content:encoded><![CDATA[<p>KeyPaths are a marquee feature in Swift 4, but it may not be obvious how to use them. One interesting use case came over Twitter:</p><h3>Dan O&#39;Leary on Twitter</h3><p>This works but really feels like I&#39;m being redundant nesting a Switch statement inside a for-loop. #swiftlang #codingwithfeels #allthefeels</p><p>There’s nothing wrong with a `switch` statement in a `for` loop, but this code has a lot of repetition. You could add the hours-for-day to the “Brewery” object, but the label for the day of the week (“Sun:”, “Mon:” etc.) is a UI detail that the model shouldn’t hold.</p><p>Along with the label, what changes for each row is <em>which</em> property to access. Storing a reference of which property to check is exactly what KeyPaths do.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7b52688bfb77afb115dc001268a1ccc8/href">https://medium.com/media/7b52688bfb77afb115dc001268a1ccc8/href</a></iframe><p>The `startTime` array defines a label together with a `KeyPath` to a property. The property is not accessed, however, until inside the loop.</p><p>Before Swift 4, the best appraoch would be a `switch`, accessing the property in each caseand returning the string that accessed the property. One disadvantage is a switch/case would hardcode the relationship of index with property; if we wanted to start the week on a Monday (Or maybe the current day, with subsequent days trailing downward) we would need to add an offset and also handle overflow. (This example still hardcodes the order in the “startTime” array, but this could be generated based on locale, unlike a hard coded switch.)</p><p>This is a simple example, but shows how KeyPaths works and hints at their potential to add new flexibility.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ab8390ded6d1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[WWDC 2017: The View from the Couch]]></title>
            <link>https://medium.com/@mikesand/wwdc-2017-the-view-from-the-couch-b1c92c7cb89f?source=rss-b277a2123ef------2</link>
            <guid isPermaLink="false">https://medium.com/p/b1c92c7cb89f</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[wwdc]]></category>
            <category><![CDATA[documentation]]></category>
            <category><![CDATA[wwdc-2017]]></category>
            <category><![CDATA[apple]]></category>
            <dc:creator><![CDATA[Mike Sand]]></dc:creator>
            <pubDate>Sat, 17 Jun 2017 22:43:16 GMT</pubDate>
            <atom:updated>2017-06-19T13:51:41.483Z</atom:updated>
            <content:encoded><![CDATA[<p><em>The following is adapted from </em><a href="https://www.meetup.com/iOSoho/events/238088947/"><em>the June 2017 talk at New York City’s iOSoHo Meetup at Vimeo</em></a><em>, originally titled “WWDC 2107: Build and Run”.</em></p><p>What a great WWDC. We saw amazing new marquee frameworks, CoreML and ARKit. We saw a real effort to address longstanding pain points, addressed in a way that shows Apple takes very seriously; other longstanding missing pieces were filled in. We saw an emphasis on accessibility, across sessions throughout the conference. We saw a more diverse speaker than ever, especially women.</p><p>And the talks were as great as ever. We saw that Apple still has amazing engineers and is producing amazing technology, and the company and the platform look as strong as ever.</p><p>We saw this through a glass, dimly. Because the same cannot be said for key elements of the conference: the video production, the accompanying documentation, and the sample code provided. The sample code had issues when we could see it at all — tales already abound of developers, chomping at the bit to try ARKit, freeze-framing videos to type the blurry visible still frames of code into their computer. It’s not too late for Apple to snatch defeat from the jaws of victory.</p><h3>Inspiration</h3><p>The title “Build and Run” was inspired by past years, when amazing technologies on display turned out to have huge caveats or hidden catches. An alternative title for this talk was “Looks Great in the Demo.”</p><p>So the idea of the talk is to take some first impressions and ask: “Does it build?”, “Does it run?” and “Does it improve my life to be worth the complexity?”</p><p>I first started watching WWDC videos as a full time iOS developer in 2013. In 2016 I was lucky enough to win the lottery toattend, and I got more insight into how WWDC worked: You attend a session, and then you go downstairs to the labs, where the engineers await, and there you ask you questions from the session, sometimes of the speakers themselves.</p><p>On the couch, there are no labs.</p><p>So the idea of this talk was to use all the resources available to see how the stuff announced actually performed. And I’ve tried to only cover things that I personally tried, and I personally built and ran.</p><p>I originally planned to talk about each subject equally. As I got started, I found I had more to say about Dynamic Type than about everything else put together.</p><p>So the following will be quick hits:</p><ul><li><strong>Swift</strong></li><li><strong>Drag and Drop</strong></li><li><strong>CoreML / NSLinguisticTagger</strong></li><li><strong>Core Location</strong></li><li><strong>Core Bluetooth</strong></li></ul><p>The largest portion:</p><ul><li><strong>Dynamic Type and Friends</strong></li></ul><p>Ending with a final quick hit:</p><ul><li><strong>ARKit</strong></li></ul><h3>Swift</h3><p>I’m not going to talk a lot about Swift because I didn’t get a chance to use most of the headline features. But many of them do fit in with the themes of this talk:</p><h4><strong>Refactoring</strong></h4><p>We got refactoring! It only took three years. I remember I the summer of 2014, downloading the first first XCode with Swift, wanting to make some change, and discovering the familiar refactoring menu was grayed out. I distinctly remember thinking, “That must be coming in a later beta.” It didn’t occur to me it would take three years. That would be ridiculous.</p><p>And at three years Swift refactoring is not even the most long-long awaited feature in the talk.</p><h4><strong>Swift 3 / Swift 4</strong></h4><p>Based on my initial impressions, you can have a project and go back and forth from Xcode 8 to Xcode 9 seamlessly. Swift 3 migration was a fiasco; the emphasis is on preventing something similar from happening again. It’s almost like someone got fired for that.</p><p>But has Apple Developer Tools prevented something similar from happening again, or has Apple merely prevented a Swift migration fiasco from happening again?</p><h4><strong>Keypaths</strong></h4><p>I like this because of the line in the presentation “Keypaths are important to Cocoa development.” It really suggests that the rich history and tradition of programming for Apple Platforms is not incompatible with the future. You can look up the old guides on Apple’s website on Key Value Coding (KVC) and Key Value Observing (KVO); they feel rickety now but I can’t wait to see the next generation of Cocoa.</p><h4><strong>JSON Encodable</strong></h4><p>Is this the record for greatest mass Sherlocking ever? Nearly 500 pods made obsolete at once?</p><h4>Access Control</h4><p>Let us never speak of access control again. Agreed.</p><h3>Drag and Drop</h3><p>This was the first thing mentioned in the Platforms State of the Union — The Platforms State of the Union, if you don’t know, is the “Developer Keynote” that happens in the afternoon of the keynote and gives an overview of everything that’s going to be in the conference. It was also mentioned first in “What’s New In Cocoa Touch,” the first session of the first day, held in the largest room and well attended.</p><p>And “Introducing Drag and Drop” was also the first session <em>after </em>What’s New in Cocoa Touch, and if you don’t know, people are lazy and don’t like to get up. This is the WWDC equivalent of running a show after the Super Bowl.</p><p>So I was super excited to try it out:</p><p><strong>Simulator doesn’t go into multitasking!</strong></p><p>I couldn’t believe it. I fired up the old simulator, and the gesture worked.</p><p>So I filed a radar. At at 2:33 am this morning (June 12) it was closed as duplicate. How this is not treated as a five-alarm fire in Apple,? Drag-and-drop is key to the future of the iPad and the iPad is key to the overall strategy. An astonishingly link in the development process to have broken.</p><p>Also, Drag and Drop is iPad only — a fact not mentioned in the PSOTU — was that because they thought people would here “It’s iPad only” and tune out?</p><p>I love my iPad, and my iPad before it. I hope the iPad continues to thrive. But if the thinking was people will hear “iPad only” and then tune out, I suspect it’s not a great long-term or medium-term strategy. (It evokes the most baffling omission earlier, And while I can see the use even inside one app, since the demo app didn’t come preloaded with any data, there was no way for me to test even that.)</p><p>Anyway, with my radar closed as duplicate, I’m done. Drag and Drop is cut for time — life is short.</p><p>And that became a theme again and again — an amazing new technology, and a weak link in the chain of developer tools to make use of it.</p><h3>CoreML</h3><p>If you had “Machine Learning” in your Keynote drinking game, you are not with us, because you died of alcohol poisoning.</p><p>CoreML seems really cool. Admittedly, I don’t know much about machine learning. First, on terminology, we should probably clear things up. There is:</p><p><strong>ML</strong> — Machine Learning</p><p><strong>DL</strong> — Deep Learning</p><p><strong>AI</strong> — Artificial INtelligence</p><p><strong>AR </strong>— Augmented Reality</p><p><strong>VR</strong> — Virtual Reality</p><p><strong>VL</strong> — Vitally Loquacious</p><p>The last I made up, of course. The thicket of terms is an issue. The Naming scheme for CoreML caused me a great deal of confusion. What is ML?</p><h4>The Framework and the Stack</h4><p>After taking with others, we realized the issue was making out what exactly “CoreML” referred to. The title page refers to “a new foundational machine learning framework”. So it’s a framework? In some senses. But there is something called a “CoreMLModel”, that gets imported into Xcode; there are other models; there is a python utility for converting them; and somehow image recognition and natural language processing fall under CoreML… or do they? Do you import CoreML to do image recognition and natural language processing?</p><h4>NSLinguisticTagger</h4><p>The NSLinguisticTagger talk cleared many of these issues up. NSLinguisticTagger, didn’t this already exist? Yes, but much better, and much cooler. Now it can do and do more reliably:</p><ul><li>Language identification — is this French, German, Thai, Burmese</li><li>Tokenization — Identifying Paragraphs, Sentences, Words</li><li>Part of Speech — noun, verb, adjective.</li><li>Lemmatization (from elementary school, “find the root word”)</li><li>Named entity recognition</li></ul><p>The last is huge. I was ready to rush forward with an app for underlining proper names in Chinese — in a language lacking capital letters, and where proper names made up of compound common words, identifying proper names is critical. So it disappointing to see that the more advance features (everything past tokenization) will be only for 8 languages, the furthest east Russian and Turkish.</p><p>Still, I greatly appreciate that supported languages were clearly spelled out, and not left to be found out later through trial and vague unhelpful error.</p><h4>The CoreML Stack</h4><p>Since NSLinguisticTagger remains a conventional API, what does this have to do with understanding CoreML? Of course, the means by which words, parts speech, and named entity are recognized in each language is different. And your app can’t use all 8 languages always — the model has to be installed, which happens when certain events happen, such as the user installing a keyboard.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ljUef1Q70OAq9RbVdnFPHA.jpeg" /></figure><p>So the stack, and the way that NSLinguisticTagger uses models that sit between it and the underlying CoreML framework, becomes more clear.</p><p>If you want to find the NSLinguisticTagger talk, don’t bother searching the WWDC app or website for “NSLinguisticTagger” or “CoreML”. The first brings no results, the second results for the CoreML intro and the image recognition talks, but not the talk we’re looking for. You have to know to search for “Natural Language Processing.”</p><p>Indexing or tagging talks by API so they can be found in search isn’t sexy machine learning. It’s much more basic.</p><h3>Core Location</h3><p>Core Location got a new permissions scheme, and I mean “scheme” in the British sense of “system” and not the American sense of scheme, which is closer to why we are getting new permissions.</p><p>I really have to take exception to the single line from the stage,</p><blockquote>“We think you’re really going to like it.”</blockquote><p>It’s a breaking change in crucial important code, requiring branching during the transition, and if we get our single chance wrong our apps will silently fail or crash. What’s not to like?</p><p>However, after looking it over, the phrasing on this was just too strong. It would have been fine to say:</p><blockquote>*I think as a user you’re really going to like it, and as a developer your app is going to get better results.</blockquote><p>So now users will always have to option to give an app only when-in-use permissions, which is great. And the new flow does make a lot of sense, and is likely to get better results. Really helpful that they got entire flow on a single slide. It’s not pretty but it’s clear, always the better trade-off:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Cx_y9L9LdIp-7W7TbRKaRA.jpeg" /></figure><p>Fortunately, also announced (but not mentioned from the Core Location stage) Objective C is getting Swift-style availability checking. It’s really great to see the best features of Swift being ported back to Objective C, without the disruption that comes with innovation.</p><h3>Core Bluetooth</h3><p>Core Bluetooth is my favorite framework, my extremely important for my postion at Raden working with Smart Luggage — and to put an integrated scale into your suitcase</p><p>Since I have such a high opinion of the Bluetooth team at Apple, it was astonishing to be informed that background APIs are <strong>now</strong> reliable in the background, including across system events like restarts. I have been through the documentation many, many times, and missed the disclaimers that we should not rely on them. But if they’re stable now, I’ll take it.</p><h3>Dynamic Type</h3><p>UIFontMetrics inspired this talk — which was set up months ago, when I had no knowledge of its existence. How?</p><p>Who here knows what Dynamic Type is? <em>(Fewer than 20 hands go up, about 10% of the audience). </em>To summarize, Dynamic Type allows the user to set their preferred text size in the iOS settings, and apps throughout the system will make all text larger or smaller. It’s not just a preference, but has important implications for accessibility, although if if you have normal vision it can prevent eye strain.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FVHDahnByUrbYvB9Qk4LIQ.jpeg" /></figure><p>It was introduced in the 2013 sessions in Text Kit and was among the first WWDC sessions I watched, since less than a year earlier I had been an editor in print. Dynamic Type is more than size, as the 2013 Text Kit sessions explained. The system won’t just change the point size, but will make other adjustments depending on what the text will be used for. So instead of callingFontWithSize, you call preferredFontForTextStyle and get a font that is sized and formatted perfectly for you. It’s really very ingenious and advanced.</p><p>In 2013 I got all this and went directly from the end of the session to Xcode to see how it went. And I got it working with the system fonts, calling preferredFontForTextStyle. And then I looked for the API to do this with custom fonts.</p><p>And looked.</p><p>And looked some more. I wasted some time that evening and in subsequent days looking for the API to use Dynamic Type with custom fonts, because it made no sense to me that Apple would expect us to do this but include no means to do so. Why wasn’t there a disclaimer that it wasn’t yet possible?</p><p>If this was only a replacement for system font of size, why didn’t they just say that and announce we could get started and in subsequent years it would be rolled out further? (In 2013 a similar disclaimer would have been appreciated for Auto Layout in UITableViewCells, which innumerable developers including myself found out was not supported through unpleasant trial and error.)</p><p>And I was perplexed over subsequent years as they repeatedly encouraged developers to adopt it. Just a few of the most perplexing:</p><p><strong>WWDC 2014:</strong></p><blockquote>We’re going to be asking that all applications that deal with text in iOS 8 adopt Dynamic Type and you’ll see in fact that all of our system apps have already done this.</blockquote><p><strong>WWDC 2015:</strong></p><blockquote>These are the text style APIs that are used for Dynamic Type, which also give you all the Dynamic Type advantages, such as users can go in their preferences, change their font size, and your app will react accordingly.</blockquote><p><strong>WWDC 2016:</strong></p><blockquote>Don’t forget things like Dynamic Type right, where the user can set a font size and all your applications are going to react and layout right, you’re all doing that?</blockquote><p>That there was no way to do this with custom fonts — which almost everyone uses — became more and more bizarre, less an omission than some kind of weird blind spot.</p><p>Furthermore, Apple did not lead by example. Among the places Dynamic Type is not well handled in iOS 10 is the settings accessibility menu<em> where you turn it on</em>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/508/1*8X3BIBJ0NlaY0pVQBfarRg.png" /><figcaption>iOS 10.3.2</figcaption></figure><p>Here is the same menu in iOS 11:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/508/1*A16IQp9Yq5kRX4zigfbJZA.png" /><figcaption>iOS 11 Beta 1</figcaption></figure><p>The great news in iOS 11 is not just that there’s an API for implementing DynamicType with custom fonts. It’s that it looks like someone has gone through and systematically asked what developers needed to support Dynamic Type, and then provided it.</p><p>In addition to UIFontMetrics, there are other APIs, some of which already existed but have been made easier. There is UIContentSizeCategory, a property not just on a UIKit object’s traitCollection—traitCollection being another iOS technical innovation that developers aren’t quite sure what to do with — but on UIApplication.</p><p>You can see in iOS 11 that the switch has moved to the next line to accommodate larger text sizes . Not only do they provide a convenient API to do this, but instead of taking the opportunity to talk up Interface Builder like a parent telling their child broccoli is candy, the sample code provides examples for programmatic Auto Layout and using <em>setFrame, </em>which they call “manual layout.” Frames were never officially deprecated, and it’s great to (belatedly) see the acknowledgement that developers who use them for whatever reason shouldn’t be left out in the cold.</p><p>The Dynamic Type session in 2017 is hitting it out of the park on fonts and layout, and then got to the question of how to handle the size of images under accessibility:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MJycpJ9TxY50EgRB2IYRCw.png" /></figure><p>So many questions! No wait, the presenter is going off stange, come back!</p><p>Apparently this had been addressed in What’s New In Cocoa Touch, which I watched live from my desk at work, before I had logical issues resolved; guess I missed something substantive when switching monitors.</p><p>This will be as big a change as the switch to @2x images with retina displays. And yet it was six slides on this topic and then over. Where was ‘Jill from Adobe’ to take the stage and show how easy it is to integrate export of PDFs into our existing workflow? Where was a systematic demonstration of how this is going to work?</p><p>Where was any reference to where we can get more information about this?</p><p>In the meantime it has fallen to outsiders to begin to explain how this works.</p><p>Phasing like “make sure you are” highlights that the presenters on stage are not working with an idea of their audience that reflect the range of organization challenges faced by developers. Are the same individuals who just sat through 20 minutes of API examples also composing assets? Are the same individuals who just sat through 20 minutes of API examples able to give orders to designers about how to conduct their workflow? Probably not.</p><p>Core Location provides an apropos contrast: Developers can take the new location permissions to their organization for the simple reason that <em>Apple says we have to do this</em>.</p><p>Yet unless Apple wants to make this an App Store rule or technical requirement — which would have negative ancillary consequences, especially for any less sensitive issue than location privacy — developers will need to see these changes within their organization. Developers will have to see this to designers, to clients, to managers. Apple gave us almost nothing to make this case.</p><p>Dynamic Type did come up in one of the “design shorts” videos. It was a great summery by designers for designers. it was also the second of three topics addressed in a ten-minute clip. So to pass this info from the design short to designers, we would to specify which range of the talk they should watch.</p><h4><strong>Sample Code</strong></h4><p>The Dynamic Type demo app brought further issues in last mile to getting developers what they need to implement this. I thought I had trouble because I don&#39;t’ care about Pokemon. But that was not the issue.</p><p>The first wasn’t anything to do with the Dynamic Type team, but not tangential because it’s a link in the chain: In Beta 1, Markdown in Xcode looks like shit.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qFN8vtGLLAwCnr0FSCeAxA.png" /></figure><p>It’s not the weird text justification on the lowest line, though what’s going on with that? The use of a half-d0zen fonts in one screen violates basic font usage. The decision to use a serif font for body when every other font is sans-serif is ridiculous; especially since of course markdown in Xcode has formatted code interspersed with body text constantly. A sans-serif would better meshed with the sans-serif font used every other place in Xcode. There’s also no way to customize the fonts.</p><p>Another issue with is that this code was called out from the stage as being a “recipe book.” There are four view controllers: It’s like a recipe book had two recipes for chicken, one for fish, one for tofu. A single example of each isn’t a good recipe book.</p><p>Finally, hope you looked at those bullet points in the markdown. Regardless, quick guess, which screen is the “BattleViewController” below?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7m8oTBAUsxkMjQbbaEcqeA.png" /><figcaption>Battle of the View Controllers</figcaption></figure><p>If you thought the `BattleViewController` is the screen that says “Battle!” you would be incorrect; that is the “ScorecardViewController”. The `BattleViewController` is the screen titled “Opponents”. There is no screen to show the battle itself, which takes place the moment you click the button; the battle is over before the run loop.</p><p>This is serious because trouble getting orientated adds cognitive load at the exact moment developers are going to figure out even more complex issues. Putting a confusing series of labels conflicts with the purpose of the code existing in the first place.</p><p>In the actual sample code, there are several good examples of how to handle Auto Layout and “manual layout” — it is refreshing to see the acknowledgement that, yes Virginia, sometimes you want to work with frames.</p><p>A final note on the presentation of the sample code. The presenter clearly knew her stuff. Unfortunately, she spoke English with a thick accent, which I could understand, but a non-native speaker of English might find impossible (When I taught English as a foreign language abroad, students told me directly a thick accent makes it much more difficult to understand. At one point I was even called on to do English-to-English translation between Chinese and South Asian speakers of English)</p><p>Hearing the speaker should not even be an issue, because the sessions should be closed captioned.</p><p>The lack of closed captioning is another regression. I remember at WWDC 2016, sessions that were broadcast on monitors on the first floor were closed-captioned live. Closed captioning should be a straightforward task if the script is provided in advance. It is embarrassing to have a conference that gave such prominent attention to accessibility to not itself be accessible.</p><p>On a related note, the WWDC app did not support Dynamic Type.</p><p>(As of this write up, videos now have a caption icon appearing on the video but read “unknown cc” and no captions are appearing.)</p><h3>Editing</h3><p>The most obvious regression in this year’s WWDC production was the video editing.</p><p>Maybe it was the move to San Jose, and if the high quality video production of 2015 and 2016 was by in-house Moscone professionals. Or maybe it was the decision to try to broadcast all sessions live, which was unnecessary, especially if it led to a regression on any other metric.</p><p>Appallingly for the purpose of WWDC session videos, many sessions showed slides for only seconds at a time, and showed only the presenters on stage in frame. Picture-in-picture, where the slide occupies the frame with the presentor in a box to provide a visual connection to the words, was mainstay of 2015 and 2016 session videos and incredibly underused this year.</p><p>Picture-in-picture should be the default, and if the slide is too packed to allow it, show the slide. Don’t forget what the goals of these are.</p><p>It is possible to hypothesize that a lack of technical appreciation led to the poor choice of editing. However, in the session “Localizing Swift Playgrounds”, at one point the presenter asks the audience to look, with an exaggerated arm movement he presses the clicker — and the shot never moves away from the presenter alone. Someone just didn’t do a very good job on the video production.</p><p>Astonishingly, when one session had to be redubbed — apparently there was an audio recording problem, though that’s not noted anywhere — the editing still showed the presenters alone in frame for long periods. We’re looking at a video with the lips and body motions off sync. The 2014 and earlier format of only slides served us all well for years — there’s no reason to not note the audio issue, show presenters when they come on and go off stage, and go to a slides-only video that served us well 2014 and before.</p><h3>ARKit</h3><p>Since I have expereince making Augmented Reality apps, I had planned to end the talk with a ARKit demo, but I spent the whole weekend fighting with Auto Layout.</p><p>ARKit is legit. I tried to come up with a better term that “legit”, in the Urban Dictionary sense of “A modern synonym for words such as ‘cool,’ ‘ill,’ ‘tight,’ or ‘dope.’ Used to describe a noun that is of a particularly excellent quality” but did not come up with anything better.</p><p>It’s such an asotinishing, amazing acomplihsment by Apple. That we can use in an apps and it will run on hundreds of millions of iPhones in the fall is incredible.</p><p>As noted, developers are now freeze-framing the . And there’s no “ARKit Programming Guide.” There’s only a single sample app that scratches the surface of the possibilities. And the ARKit Framework page has an odd mix of links to classes and links to restanding pages, under the heading of “Topics.” It’s very hard to see how to reach a starting point here.</p><p>(A larger look at the “new documentation” is beyond this, except to assert it is a huge regression. Appallingly, class references and protocol references <em>do not include return values</em> in the list. Since a function without a return value is valid, there’s no way to know if a function has a return or not without clicking through.)</p><p>Also, there’s no sample code anywhere. In fact, trying to find any sample code throughout Apple’s developer documentation is now a scavenger hunt.</p><p>If this is the future of developer documentation then Apple hasn’t learned the past lessons of dynamic type, Swift migration failures and others, and expect WWDC 18 to feature prominent corrections of these shortcomings.</p><h3>Conclusion</h3><p>Would I want to live in an alternate world where this talk ended</p><blockquote>What Apple announced at WWDC was meh, but production values were great and the sample code posted immediately!</blockquote><p>Of course not. But the videos and documentation and sample code are spans in the bridge to bring these technologies to developers and on to users.</p><p>Moreover, at WWDC Apple Engineers talks to thousands of developers — literally, thousands. There are hundreds of thousands of developers who they didn’t talk to, who still have unanswered questions.</p><p>The lesson of past years is to not assume that Apple knows these issues exist, and like Swift 3 migration and missing Dynamic Type APIs, they problems are so obvious that of course there’s a fix the works coming soon.</p><p>And it’s not because developers are whiny and demanding — we have the same goals! If the serious issues with videos and documentation and sample code aren’t resolved — in weeks, not months or years — then our lives are going to be more difficult, less developers are going to use these new amazing technologies.</p><p>We really lucky to get to work in this field, and we owe that to Apple. We have the same goals, and let’s communicate, and all move forward to this amazing future together.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b1c92c7cb89f" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>