Archive for the ‘Xcode’ 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: 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: 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.

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.

Adding syntax highlighting and source file support for TypeScript to Xcode

Thanks to a prior solution created by Steve Troughton-Smith for Lua, I was able to hack together an Xcode Plug-In (yeah, those still exist) for 10.1.

TypeScript repo is here at github.

To install, quit Xcode. Run setup.sh to add the xclangspec and ideplugin info to your ~/Library/Developer/Xcode folders. Then launch Xcode, agree to allow the plug-in to run, and then add your ts files.

The file inspector will still say they’re MPEG-2 Transport Stream files but you’ll be able to see the text, the text will be formatted, and you can use Xcode to search for content within the files. Let me know if it works for you.

The xcplugin and the xclangspec were easy to put together, because I just riffed on JavaScript’s syntax. Other languages will take a bit more work because you have to set up a list of keywords and their characters and syntax coloring rules, which may or may not lend themselves to easy lexer support.

Xcode Symbology Challenge! Find examples, identify icons, gain fame and glory

You know those little icons in the Xcode developer docs? Like the 4 squares for frameworks or the M for method? How many can you find and give examples for? Also how many can you identify off the top of your head? Do you know what each of these are and what they represent?

What follows is an exhaustive list sourced from an internal Xcode framework. For each of the following, your challenge is to describe what the icon looks like and offer an example that uses the icon. For example “T” is a type alias. You can find one by following UIKit > Drawing > UIGraphicsPDFRenderer.DrawingActions or searching for DrawingActions.

  • article
  • category
  • class
  • class extension
  • constant
  • endpoint
  • enum
  • extension
  • field
  • framework
  • function
  • group
  • local_variable
  • macro
  • method
  • object
  • operator
  • property
  • protocol
  • sample code
  • struct
  • subscript
  • typedef
  • union
  • variable

Have fun and drop a comment with a link to your finds. Please don’t put answers here directly as that may spoil the challenge for others.

Prototyping CoreGraphics in the Playground

No matter how flaky, I love using playgrounds to prototype Core Graphics, SpriteKit, and many other see-as-you-go technologies. They’re fantastic for building out specific custom content with a bare minimum of coding investment. You get a lot of win for very little time.

I was helping someone out the other day, explaining the strokeEnd keypath (versus the path keypath) and building a playground showed it off to perfection.

Admittedly, it helps to have quick helper code on-hand for quick starts. I have playground-specific setup code, handing me a view controller (called vc) and a centered view, ready to start demo-ing in this one.

I also have a couple of pages of code (like the layer(path:) constructor, the animateStrokemethods, and the schedule() utility off page, in the support module. They’re all highly reusable. It’s a pity in-playground debugging is so dreadful. It would be an ideal module-building tool if not for that: build and explore (and ideally build tests) in a single place, without having to be in a fixed workspace lacking the exploration feature. Adding “convert this exploration into a test” would be icing on top.

I’m disappointed that playground-specific visualizations built for teaching and demos don’t transfer to the debugger for real-world production support. I don’t see any reason why a CGPoint instance should get a pretty graphic representation but a CGAffineTransform, for which I have quite a full presentation, does not.

I can use custom mirroring to produce valuable output for dump, and therefore for printing objects in the debugger but not for debug quicklooks. Plus as far as I can tell the custom NSObject-only quicklooks haven’t been updated in years and there’s no hint of extending this to structs and enums.

By the way, what’s the deal with all the API audits? How long are these going to go on? If you thought updating the app delegate was a minor nuisance, you haven’t seen what’s happened to all the constants and Core Graphics APIs. This update is huge and disruptive…

Converting projects by hand to Swift 4.2

If Xcode is acting up for you the way it is for me, you may want to step back from automated migration and just do it by hand. I spent far too much time this morning trying to get Xcode to finish migrating for what were extremely trivial changes.

If you’re going by hand, make sure to change your “didFinishLaunching” launch options (in your App delegate) from [UIApplicationLaunchOptionsKey: Any] to use UIApplication.LaunchOptionsKey. (Notice the period in the name.)

To set the compiler from Swift 4 to Swift 4.2, open Target > Build Settings. Navigate to Swift Language Version and use the pop-up to select the proper compiler:

For some projects (especially small sample code) this alone may be sufficient to get you back and working.

Simulators gone bad

Recently, some of my simulators launched and loaded just fine. Others simply went black. It didn’t seem to matter which firmware I was simulating. Some devices were just happier than others.

Naturally, I turned to the system console, which provides device-by-device logs, but I couldn’t really find anything.

I tried restarting and rebooting the sims. I tried resetting the core simulator service. I tried a lot of things. (No actual chickens were harmed.) Finally, I stumbled across a Apple Dev Forum thread about issues with the beta system. The advice offered in-thread was this:

  • Quit the simulator. (I also killed com.apple.CoreSimulator.CoreSimulatorService because reasons.)
  • Run xcrun simctl erase all
  • Set a framebuffer renderer hint: defaults write com.apple.CoreSimulator.IndigoFramebufferServices FramebufferRendererHint 3

It worked.

Yay! \o/

From the thread, apparently hints 1 and 2 do not work but 3 does. An Apple Engineer noted that, “hint 0 is auto (currently prefering Metal and then falling back to OpenGL if unavailable). Hint 1 prefers Metal and hint 3 prefers OpenGL. Hint 2 used to mean OpenCL, but we dropped OpenCL support.”

Upshot is that I lost many hours but I seem to have a working solution for dealing with a common problem. I hope this write-up helps you if you encounter the same issues.

Update: Guru Russ Bishop recommends against using this long term. He writes

If you (as I) have deadlines, and cannot wait for this problem to be fixed, this fix will get you back to work. Russ reminds me, though, “Use it temporarily only if you have this problem, and don’t forget to delete the pref in the future”