Archive for the ‘Development’ Category

SwiftUI: Modified Content, Type Erasure, and Type Debugging

When working with declarative views, you should be able to reach for a full tool suite of functional application. In a typesafe language like Swift, things can prove more difficult than you’d might first think. Consider the following code:

What is core‘s type? It isn’t Text. It’s actually an application of modified content, specifically Text passed through a rotation effect:

Just add a background color and a shadow and the type jumps to this:

You might ask: why is this a problem? After all, Swift is doing all the heavy lifting, right? In my case, the answer lies in my struggle to incorporate this core image into a multi-stage bit of text art using reduce. Paul Hudson tweeted a step-by-step approach to this and I was sure I could make it simpler and more elegant.

And that’s where I started throwing myself against what at first seemed like an impenetrable wall for a couple of hours. Between SwiftUI’s stroke-style Dysarthria error messages and the typesafe system, my attempt at creating a solution along these lines felt doomed:

[Color.red, .orange, .yellow, .green, .blue, .purple].reduce(core) { view, color in
  view.padding()
    .background(color)
    .rotationEffect(theta)
}

The code wouldn’t compile and the error messages couldn’t tell me why. The problem? Each stage created a new layer of modified content, changing the type and rendering reduce  unable to do the work. It was only with the help of some deep-dives into the docs and advice from colleagues that I was able to arrive at a solution.

Type erasure, using SwiftUI’s AnyView struct enables you to change the type of a given view, destroying the nested hierarchy. Importantly, it creates a single type, allowing a reduce operation to proceed.

At first, I used AnyView the way you’d typecast in Swift, namely:

AnyView(view.padding()
  .background(color)
  .rotationEffect(theta))

But I hated that. It sticks out as so Un-SwiftUI-y, with the parentheses spanning multiple lines and throwing off the clear logical flow. If you’re going to go fluent, just go fluent. So, eventually, I decided to create a View type extension to handle this:

extension View {
  /// Returns a type-erased version of the view.
  public var typeErased: AnyView { AnyView(self) }
}

The result looks, instead, like this:

view.padding()
  .background(color)
  .rotationEffect(Angle(radians: .pi / 6))
  .typeErased

And yes, I went with a property and not a function as I felt this was expressing a core characteristic inherent to each View. I can probably argue it the other way as well.

From there, it wasn’t much of a leap to ask “what other fluent interface tricks can I apply”, and I ended up putting together this little View extensions for inline peeks:

extension View {
    /// Passes-through the view with debugging output
  public func passthrough() -> Self {
    print("\(Self.self): \(self)")
    return self
  }
}

This prints out an instance’s type and a rendering of the instance, which will vary depending on whether there’s a custom representation, passing the actual instance through to whatever the next stage of chaining is. I don’t use it much but when I do, it’s been pretty handy at taking a peek where Xcode’s normal QuickLook features hit the edge.

In any case, I thought I’d share these in case they’re of use to anyone else. Drop me a note or a tweet or a comment if they help. Cheers!

Update: It suddenly occurred to me that I could make this a lot more general:

extension View {
  /// Passes-through the view with customizable side effects
  public func passthrough(applying closure: (_ instance: Self) -> ()) -> Self {
    closure(self)
    return self
  }
}

Isn’t that nicer? The equivalent is now:

struct MyView: View {
  var body: some View {
    [Color.red, .orange, .yellow, .green, .blue, .purple]
      .reduce(Text("👭")
        .font(.largeTitle)
        .rotationEffect(Angle(radians: .pi))
        .typeErased)
      { view, color in
        view.padding()
          .background(color)
          .rotationEffect(Angle(radians: .pi / 6))
          .passthrough { print("\(type(of: $0)), \($0)") }
          .typeErased
    }
  }
}

And I can put any behavior in from printouts to timing to any other side effect I desire. To all the functional purists out there, I sincerely apologize. 🙂

SwiftUI: Handling optionals

A friend recently asked me if I’d write a few words about SwiftUI and optionals. Like nearly everything in SwiftUI, you have to rewire your brain a little bit when thinking about this because SwiftUI is perfectly happy working with optional views, such as Image? and Text?.

The tl;dr of this post is going to be “use map” but before I get there, let me dive in a little deeper. And, of course, whatever I got wrong, please let me know so I can learn more and correct this.

You can feed SwiftUI an optional view, such as Text? with the understanding that the system will only render non-nil values. Here are some screenshots that show the output in both cases:

But what happens when you want to work with optional data that’s driving your view layout? You don’t want to use nil-coalescing (unless you have some compelling backup view case). Instead, if you want to render without a backup value, you have to dig a little deeper. Don’t automatically reach for the familiarity of conditional binding. You can’t if-let in SwiftUI the way you expect to:

My “clever” workarounds really weren’t very clever:

Although, SwiftUI supports the if-statement, prefer map as your first line of attack:

You can see how much more elegant the map version is in comparison. Force-unwraps make unicorns cry and contribute to overall levels of human misery. That’s not to say that if isn’t useful, rather it’s just not my preferred approach for optionals in SwiftUI:

VStack {
  Text("Top")
  if name != nil {
    Text(name!)
  }
  Text("Bottom")
}

(Note: I’m exploring @ViewBuilder closures right now and there’s some really cool stuff including buildEither and buildIf content that I haven’t dived deep into yet.)

Be especially careful and read the documentation when you think you’re going to be working with failable initializers because sometimes you won’t be. For example, SwiftUI’s Image does not use a failable initializer.

I can’t tell given the current stability of the system whether Image(systemName:"notarealname") returns an empty image, which I guess wouldn’t be too bad, or always crashes (I’ve had a bunch of bad crashes) but my most common outcome is a frozen playground with a severe emotional breakdown cowering in the corner and hugging itself.

I emphasize this gotcha because you might not catch the potential meltdown if you only pass it well behaved strings during testing (as in the following case). It’s important because it can bite:

In contrast, UIImage uses a failable initializer and returns an optional, which you can map through an Image with consistent good outcomes at each point:

If you want to get really OCD about all this stuff, you could add an extension on optional that allows you to include a visual error instead of omitting the view, but I’m not entirely sure that’s tremendously useful:

I’m out of time and have to head back to work. Thanks for having lunch with me.

SwiftUI: Modal presentation

I have regrettably little time to devote to SwiftUI. I explore when I can, although I wish I were a lot further in that journey.

Here’s my latest go, where I’m looking to build a modal presentation. Today is the first time I’ve been able to play with Modal, the storage type for a modal presentation. I tied it together with an isPresented state, but I’m wondering if I’ve done this all wrong.

I can’t help but think there’s a better way to do this. I’m using a text button for “Done” instead of a system-supplied item, so it won’t be automatically internationalized. Nor, can I find any specialty “Done” item in SFSymbols. When looking at Apple’s samples, such as Working with UI Controls, I see the same Text("Done") . While I know that Text elements are automatically localized should resources be available, is SwiftUI providing us with any core dictionary of terms?

I think using the isPresented state in the code below may be too clunky. I’d think that there would be a more direct way to coordinate a modal item. Any advice and guidance will be greatly welcomed.

I remain stuck in Mojave for most of my work, although I put an install of Catalina on a laptop. Although you can build proper SwiftUI apps using the beta Xcode, without the preview (and I’ve had no luck finding a secret default to enable it under Mojave) makes the experience way slower than working in a playground.

I’m hoping to dive next into Interfacing with UIKit.

SwiftUI: Boing!

Source: here

Note that you add the animation to the View object and update the view’s state in the gesture state handlers. The onEnded action passes a summary of the velocity, offset, and location of the gesture but I ignored it because I didn’t need it.

SwiftUI: Embracing the nonobvious?

This is going to be another day where I get to play with SwiftUI because I can’t get any real work done right now and am dealing with lots of interruptions.

This morning, I returned to yesterday’s mouse inventory sample to try to get my rounded corners working. Several people suggested that I implement my interface using a ZStack and a Rectangle, so I tried that first.

To my surprise, the Rectangle expanded my VStack and I haven’t to date figured out how to constrain its size to be no more than its sibling. I wanted the rectangle to grow weakly instead of pushing the title and total items towards the edge of the parent view, the way it did in this screenshot:

Here’s what it looks like without the monster-sized Rectangle, which I think is a much more appealing layout:

So instead, after messing around a bit, it occurred to me that everything is a view or at least everything is kind of view-ish and if so, then I could possibly apply my corner rounding to Color, which I did.

}.padding()
.background(Color.white.cornerRadius(8))

And surprise, this is what I got:

Isn’t that cool?

Although the final layout is exactly what I wanted, if you think about it, it’s not that intuitive that system uses tight placement for this and lax spacing for the one with the Rectangle.

In fact, as a developer, I’m not happy about not having direct control over the tightness of either layout or an obvious way to relate ZStack siblings. If there’s a way to describe how much content hugging I want in a ZStack layout and how to prioritize which item in that layout should guide the others, I haven’t discovered it. If you have, please let me know!

I’m still trying to learn to best use the deeply mysterious Length (and, no, don’t tell me “it’s just CGFloat“, because clearly it isn’t “just” that with all the Angle, Anchor, GeometryProxy, UnitPoint stuff,  and so forth) and apply layout relationships. Today, time allowing, I’d certainly like to learn more about the mysterious TupleView, a View created from a swift tuple of View values and see where it is used, the ForEach, which computes views on demand, Groups, EquatableView, and so forth.

SwiftUI: A little state

I wish I had more time to play. Here’s a little SwiftUI thing I threw together in the few moments I had free today. The source code is here.

Interestingly not including Color for backgrounds seems to kill my poor little sample. I suspect an overload where the type cannot be unambiguously inferred. Adding corner radiuses (shown here on the outside) destroys user interactivity. I have it commented out in the gist.

Originally, I tried to control state extrema (no negative inventory) in my model object but that led to a disconnect with the steppers. Instead, I finally found an initializer that allowed me to specify the valid range (in: range) to sanitize the user input, and disable the minus button for zero values.

A lot of the time I spent putting this together ended up with “helpful” results that looked like this:

That is to say, it’s really hard to provide a fluent functional framework in a typesafe language that feels like you’re constructing things into type erased collections because you never actually are…if that makes sense.

So far this week, I’ve managed to watch one video (the keynote) and about 20 minutes of another (the first bits introducing SwiftUI). I hope I have a chance to catch up. I’ll try to keep notes here on the website as I work through some of this stuff. It feels weird this year how far behind I am due to work commitments.

I spent today out of the office due to personal commitments and it’s been the first time I could really dive in (well, “dive” meaning for 10-20 minutes at a time here and there during the day). Loving this stuff, can’t wait to do more.

Good Things: SwiftUI on Mojave in iOS Playgrounds

Yes, you can upgrade to the Catalina Beta. Or, you can keep getting work done on Mojave and still enjoy the glory of SwiftUI exploration.

  1. Install Xcode 11 beta along side your 10.2.x Xcode
  2. Using the beta, create an iOS playground. (This won’t work with macOS, which attempts to use the native frameworks, which don’t  yet support SwiftUI)
  3. Import both SwiftUI and PlaygroundSupport.
  4. Set the live view to a UIHostingController instance whose rootView conforms to View.

Here’s an outline of the basic “Hello World” setup:

From there, you can create pages for each of your SwiftUI experiments, allowing you to build short, targeted applets to expand your exploration and understanding of the new technology.

Bad things: Extension Access Control

Swift extends the courtesy of an access control annotated extension to its top level members. I’m going to call this “inheritance”, but I know there’s a better name for this but I just don’t know what it is.

Consider the following:

// Base type is public
public struct MyStruct {}

// Here, the extension is declared public, so each top level member
// "inherits" that access level.
public extension MyStruct {
  // This is public even if it is not annotated
  static var firstValue: String { return "public" }

  // This is also public but the compiler will warn.
  public static var secondValue: String { return "public but warned" }

  // This class is also public via "inheritance" 
  class PublicSubclass {
    // However, its members must be annotated. This is public
    public static let publicValue = "public"
    // This defaults to internal
    static let internalValue = "internal"
  }
}

In this example, firstValue inherits the public access level from the MyStruct extension. The explicit annotation for secondValue is warned by the compiler as unnecessary.  If you treat warnings as errors, that’s a problem.

Each of the static properties are accessible outside the module except for internalValue, as even in a public class declaration, its members do not inherit its control level:

Before I start putting some preliminary style guidance out there, I’d like to point out a few more things about this. Here’s a second example:

internal class InternalType {}

extension InternalType {
  public static var value: String { return "value" }
}

Swift compiles this code without error. It is clearly a developer-sourced issue. The intent to make the member public is fundamentally flawed. as it exceeds the type’s access control level. This issue also exists outside of extensions, where the compiler will not warn on too-high levels for direct type members:

internal class AnotherInternalType {
  public var value = "value" // no warning
}

You’d imagine this is a place where the compiler should up its game, no? This is a point of code that is technically functional and compilable but whose specification undercuts the documenting nature of using access control. Shouldn’t the annotation be limited and warned here?

The compiler will find mismatches between the extension ACL and the type ACL:

And that’s where the problem comes in because the guidance I’m working on says: “Do not annotate extensions with access control levels except when working with trivial utilities”. Skipping extension ACL ensures that you can meaningfully and intentionally add access control to each member declared within that extension. Each access level is co-located with the declaration it decorates. This makes your code more easily audited and its access levels will be immediately apparent as to intent and implementation.

What are your thoughts? Can you think of any reasons why extensions should ever be ACL’ed in production code? And is this just a bug/language enhancement thing or is there something I’m missing. Thanks in advance for your feedback.

Teaching collections: shifting paradigms and breaking rules

Just because some things look alike and may act alike at some level, doesn’t mean that they should be taught at the same time, under a unified umbrella of learning. Consider bagels and donuts. They are both toroids . You can layer several instances onto a stick for storage or serving. You can cut them both in half. If you have no taste or sanity, you can place custard — or, cream cheese, salmon, onions, and capers — interchangeably between the two sides of either item.

Despite these common API surfaces, their use-cases, edge conditions, and recipes share little overlap. Conformance to ToroidFoodstuff does not correlate with each preparation of dough, the cooking process, or the serving and accoutrements associated with either food.

So why do we always have to lump arrays, sets, and dictionaries into a single lesson on collections?

A new language learner has little interest in traversing dictionaries, although it’s possible, or taking a set’s prefix, which is also allowed. Nor are new learners always prepared to take on optionals, the core return value for dictionary lookups, early in the language learning process.

I’ve recently spent some time helping to outline an introductory sequence for Swift learning. I pitched eliminating collections as a single topic unto itself. I want to reject superficial similarity and build language skills by introducing simple, achievable tasks that provide measurable and important wins early in the learning process.

Take arrays. They can store numbers and strings and more. You can grow them, shrink them, slice them. They have a count. They have indexes.  Arrays are perfectly matched with iteration in general and for-in loops in particular. Arrays and for-in iteration work hand-in-hand. So why not learn them together?

The answer is generally that arrays belong with collections and for loops belongs within a larger set of iteration topics. Ask yourself whether new coders actually need while and repeat-while loops in their initial approach to the language? How often in normal Swift coding do you reach for those two for simple reasons in simple code?

I’m not saying while-loops shouldn’t be taught. I’m trying to figure out what sequence of incremental learning provides new Swift developers with the most coherent set of basic tools they need to express themselves and expand their understanding over time.

Every classroom minute spent mastering while is a minute that could expand and practice for. Introductory lessons should focus on the core terms and patterns most commonly used in the workplace. Expressive language vocabulary can always be expanded through practice and engagement. Classroom minutes represent the restricted path.

Dictionaries, I argue, should be taught late. Every lookup is tied directly to optionals, a dictionary’s native return type. And optionals are quite a conceptually heavy topic. Dictionaries are the perfect pairing.  The type is a natural source of optional output, and an opportunity to discuss nil-coalescing and default fallbacks.

From there, you can pull in failable initializers, and optional chaining.  Dictionaries also lend themselves to advanced concepts like (key, value)-based for-in loop tuples, the key-value basics of Codable, and how custom structs relate to key-value coding, not to mention the entire conversation about nil, errors, try?, and more.

As for sets, well, I love sets and use sets, but are sets even appropriate for new learners outside of some sense of “completionism” learning? Should they be taught only because they’re one of the “big three” collection types? I’d argue that people should learn sets when they are already proficient in core language basics, not in the most introductory setting.

For example, you can tie sets into a lesson on view touches. Just because they’re a collection doesn’t mean that the newest students have to learn every collection right away, just as they don’t need to learn NSDictionary, NSArray, and AnyObject, and so forth, in the first days or weeks of exposure to Swift.

Trying to structure a plan to create a solid foundation of incremental learning is a challenging task for any non-trivial topic. When it comes to Swift and Cocoa/Cocoa Touch with its vast range of potential interests, ask the questions: “What core concepts and patterns best reward the language learner with immediate benefit?”, “What grouping conventions should be tossed overboard to better focus on the skills with highest returns?”, and “What critical paths allow learners to proceed towards measurable skills and performance with the least overhead?”

Justify each topic with an answer that’s not “it’s covered that way in the Swift Programming Language book”, especially when working with new learners versus developers moving into the language with existing programming experience. And even when teaching more experienced students, let the daily realities they’re trying to move towards mold the curriculum of what you choose to teach.

The best learners teach themselves. The best curriculum sets them up to do so.