Archive for the ‘Tricks of the Trade’ Category

Cleaning up SPM builds and other SwiftPM thoughts

If you’re short on space and want to clean up your local Swift Package Manger repos, you can easily remove build products by issuing:

UsefulModifiers% swift package clean
UsefulModifiers%

This is particularly helpful for people, like me, who develop in Xcode where it’s easy to clean your product’s build folder but forget that there’s also mess with SPM. GrandPerspective or any of the other file space visualizers is great for seeing where your clutter builds.

Also, while I’m chatting about SPM builds, I find that a lot of people forget that swift package init offers separate initializers for library and executable. Just pass --type library for example. I’m doing a lot of library and executable work these days so it helps to have that set up for you.

I’m not crazy about everything that SwiftPM sets up, so I’m finding myself more often creating my manifests by hand.

I use a global git ignore file located in my home directory, so one of my first steps is to always dump the .gitignore that SwiftPM creates for me.

[core]
	editor = vi
	excludesfile = ~/.gitignore_global

I populate my git ignore file with gitignore.io. It’s a great resource for building savvy collections. Mine includes, among others, ignore groups for Xcode, Swift, Objective-C, macOS, Emacs, CocoaPods, Carthage, SwiftPM, and more.

I automatically add CHANGELOG.md and LICENSE.txt files, which I think SwiftPM should consider doing as well.

When developing in Xcode native, make sure you are using the right source and test folders. Notice that the preceding screenshot has both Sources and UsefulModifiers. I’m currently leaning towards reconfiguring my Xcode project to use the default SwiftPM folders but I’ve also gone the other direction. For example, you can set your target path: to specify where to look for your source material to compile:

    targets: [
        .target(
            name: "UsefulModifiers",
            dependencies: [.product(name: "ArgumentParser", package: "swift-argument-parser")],
            path: "UsefulModifiers/"
            ),
    ],

Always confirm that the default Swift version in the comment at the top of the file is the one you want to work with. I recently spent time updating my Swifts back to 5.1 so they’d run on Mojave systems:

// swift-tools-version:5.2

Of course, if you’re building new libraries of modifiers and views for SwiftUI, make sure you’re using the latest tools.

Speaking of “latest”, it’s important to think about version drift when it comes to your dependencies. I’ve been leaning towards always freezing my dependencies for any distribution to ensure that my code will keep compiling until I’m ready to move those dependencies forward.

Setting an exact dependency avoids the unnecessary pain of your dependency updating (SAP at the moment is 0.2.0) and your code dying as a result:

    dependencies: [
      .package(
        url:"https://github.com/apple/swift-argument-parser",
        .exact("0.1.0")),
    ],

At the same time, I think one of the most exciting things this week for me was Xcode’s automatic search and support of views and modifiers. Building a smart package that can be added to normal app development and updated over time, and whose bounty automatically appears in the resource library is just marvelous.

I thought I’d share some SwiftPM thoughts as I put together exactly that. Are you building your own View and Modifer libraries? Anything public? I’m curious as to what everyone else is working on!

Removing trailing white space

Your linter might find it, but did you know there’s an easy regex approach to removing trailing whitespaces from lines?

Andrew Wagner reminds me that there’s also a built-in setting:

I have this set but for whatever reason, pasting or re-indenting, I always seem to end up with a few scattered around.

If you like, you can start by visualizing the spaces by enabling Invisibles. This switches Xcode’s editor display mode to show all characters including whitespaces. It’s also a great way to track down invisible extra characters you may have entered accidentally while coding. This happens to me enough on a regular basis that I reach for this mode when it happens.

If you don’t like Invisibles mode or you want to go back once you don’t need it anymore, just switch it off in the menu. This menu is also helpful for getting rid of the minimap and listing commit authors.

Next, do a Search/Replace. Make sure to set the match to Regular Expression. The pop-up is towards the right:

Replace one or more (+) horizontal-only spaces (\h) that extend to the end of the line ($) with a blank/nothing replacement. Horizontal spaces won’t gobble up empty lines within your code as well as the trailing spaces.

Reader Rob adds: “I use ‘;$’ to remove the semis from swift code that a lifetime of C and Objective C (and other langs) have caused me to insert unconsciously.”

Helpful? Or did I mess something up? Let me know.

Coloring SVG assets in SwiftUI

Update: Huge thanks to Justin.

Retain the same code as the system image but use the asset inspector to change the SVG resource to a template image! So much easier and better. Thank you, Justin!


Coloring a SFIcon is simple. Here’s the default rendering:

struct ContentView: View {
  var body: some View {
    Image(systemName: "bandage")
      .resizable()
      .aspectRatio(contentMode: .fit)
      .padding()
  }
}

And here’s the same using a red tint:

Image(systemName: "bandage")
  .resizable()
  .aspectRatio(contentMode: .fit)
  .foregroundColor(.red)
  .padding()

But what about the new SVG image support? (The seal image is by mungang kim, the Noun project):

SVGs carry their own color information. I edited the seal in Adobe Illustrator CS4 (I have a computer dedicated to Mojave) to add intrinsic colors:

Again, the foregroundColor(.red) modifier is ignored and the native colors are shown. From my developer’s point of view, what I want is to be able to modify the SVG asset to use normal SwiftUI coloring. So the first thing I did was to create a ZStack and use blending modes to set my foreground color.

I finally got my first hint of victory by using a content blend with .colorDodge:

I discovered, though, that dodge wasn’t a great choice for non B&W assets. I needed a better blending mode.

When I tried to layer images in a ZStack, I discovered the color mode would bleed through:

I needed to:

  • Use a better blend mode that wouldn’t be affected by the SVG Image source colors and whether they were native Color s (like Color.red or system ones (like Color(.red), which uses UIColor/NSColor).
  • Isolate the blend mode so it wouldn’t affect other Views.
  • Move that functionality to a simple modifier, allowing a SVG Image to blend with a color.

I soon discovered that the sourceAtop blend mode got me the coloring I needed, whether I used the B&W or colorized asset:

ZStack {
  content
  color.blendMode(.sourceAtop)
}

Then, I needed to isolate the blend. I first turned to .drawingGroup(opaque:false) but it kept failing to provide the result I was aiming for until I discovered that isolating that into its own VStack bypassed any blends with ZStack elements at the same level:

VStack {
  ZStack {
    content
    color.blendMode(.sourceAtop)
  }
  .drawingGroup(opaque: false)
}

I then moved this into a custom View modifier:

public struct ColorBlended: ViewModifier {
  fileprivate var color: Color
  
  public func body(content: Content) -> some View {
    VStack {
      ZStack {
        content
        color.blendMode(.sourceAtop)
      }
      .drawingGroup(opaque: false)
    }
  }
}

extension View {
  public func blending(color: Color) -> some View {
    modifier(ColorBlended(color: color))
  }
}

This allowed me to create a standard SwiftUI ZStack that used the modifier in a normal cascade:

struct ContentView: View {
  var body: some View {
    ZStack {
      Image(systemName: "bandage.fill").resizable()
        .aspectRatio(contentMode: .fit)
      
      Image("ColorizedSeal")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .padding(100)
        .blending(color: Color(.red))
    }
  }
}

Here’s how that renders:

You’ll want to make sure the blending happens after the image resizable and aspectRatio calls but other than that it can appear before or after the padding.

What I got out of this was a way to use Xcode 12’s new SVG asset support, standard SwiftUI layout, and flexibility when applying my color blend to assets that might not just be black and white.

I hope this helps others. If you have thoughts, corrections, or suggestions, let me know.

The silly delight of the Xcode document opening `xed`

Julian Kahnert recently introduced me to xed, a command-line built-in that opens individual documents in Xcode. You give xed the name of a file (or files) and presto, it launches in my favorite IDE.

There’s some intriguing flexibility to xed. You can request that Xcode remains in the --background or specify a --line number to select once open. The line number request affects the last file in the invocation. In addition to passing it files to open, you can --create new files with the contents of stdin: promising for scripting and code-gen utilities.

If you pass --launch, xed promises to create a “new empty unsaved file”,  without involving stdin. Unfortunately, in my experiments with it over the past week, I’ve found that while it’s very good at opening a single file, complex commands can sometimes confuse the poor geriatric utility. xed was introduce way back in Xcode 3.0 and it kind of shows its age at times.

Even just limiting my xed use to opening a file for editing, it’s a neat little discovery for me, so thank you Julian!

Our discussion arose out of my own little utility xcopen, which I put up on Github. Mine looks in the working directory for an xcproj and then opens it. (I got tired of either working through the file completion, when there’s always a subdirectory with the same name as the xcproj or having to open Finder and then launch.)

I really like the idea behind xed and I’m half tempted to extend the feature set in xcopen using AppleScripting to get the promise of xed with a more reliable delivery platform.

The surprising joys of Preview

For years, I’ve been saying how surprising macOS’s Preview app is. Just about everyone knows it is _there_ and lots of people use it to look at pictures and crop and occasionally to annotate. But there’s so much more that Preview can do.

Did you know that you can use Preview to scan and fill out forms using nearby Phones so you can get paper work done and submitted? That’s just one underused feature. It syncs with the phone’s document scanner, to find the outlines of the paper, then performs geometry correction so you can fill out paperwork, whether it’s for your next group hike or your kid’s camp outing. Fill, sign, send, and you’re done.

Preview can also be your new lightweight drawing program, whether you want to work with shapes and text or with freeform lines:

Preview can also adjust photo levels for basic color corrections. The right-hand side is the original. The left shows the picture after I applied auto levels, upped the contrast, and warmed the picture slightly. (Yes, that’s me on the left, and my son on the right in the Powerade reflection.)

I’m not sure who gave the Preview team the go-ahead to add lots of silly and delightful features or whether this is just a dogfood target that somehow got shared with the public, but there’s just so much you can do with it. The other evening, my daughter had begged for a watchkit app and I used Preview to populate my XCAssets for the watch app icon.

If I can get enough people to sign up, I’ll be giving a workshop this week on Preview through Try Swift World, although it’s a bit of a hard sell given how weird a topic it is for an audience of developers.

What’s your favorite hidden app feature that few people know about?

“mint” (a simple SwiftPM installer) has improved my command line life

SwiftPM’s lack of an easy install feature has long been an issue of mine and for other people too. As the linked forums thread suggests, to accomplish this for a general audience requires some careful thinking: adding to /usr/local/bin is not always the best solution for every user.

Still, it’s a feature whose absence is notable. To fill the gap, I’ve discovered Yonas Kolb’s mint. Thank you to Leo Dion, who introduced this to me. It is ridiculously simple to use. Could it get easier than mint install erica/now? Admittedly my github id is short and so is my project name, but I think my point stands…

Yesterday, I hastily added a SwiftPM project to remind so it too could be installed via mint. Suddenly, adding the project specification is no longer an afterthought but a driving feature. It’s made SwiftPM support far more valuable to me for executables.

Make sure you name your primary file main.swift, your product to .executable, and if you’re developing in Xcode, override your path to point to the Xcode-project-style folder for the source files, usually the same name as the project itself. I mention this because Xcode by default (File > New > Swift Package) builds library projects, not executable ones. At the command-line use swift package init --type executable.

// swift-tools-version:5.2
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "remind",
    platforms: [
        .macOS(.v10_12)
    ],
    products: [
        .executable(
            name: "remind",
            targets: ["remind"]),
    ],
    dependencies: [
        .package(url: "https://github.com/apple/swift-argument-parser", from: "0.0.6"),
    ],
    targets: [
        .target(
            name: "remind",
            dependencies: [.product(name: "ArgumentParser", package: "swift-argument-parser")],
            path: "remind/"
        ),
    ],
    swiftLanguageVersions: [
        .v5
    ]
)

As for mint itself, you can build it or install it via HomeBrew: brew install mint.

If you have any suggestions on how I can improve my SwiftPM work, better integrate tagging, or any other tips, please let me know. Thanks!

Broken App Store downloads on Mojave: We could not complete your purchase

This has been happening to a lot of people recently. You open App Store and try to update apps or download new ones. Instead:

And if you have 48 apps to update, you have to click OK 48 times. Argh.

I spent nearly two hours with Apple yesterday trying to resolve.

Instead, I should have just tweeted because when I did Bas Broek had the answer almost immediately:

I had already rebooted, reset NVRAM/PRAM, cleaned out my Application Support for the App Store, and, get this, at the advice of Apple itself, reinstalled freaking Mojave to try to resolve it.

What a waste of time.

I hope this may come up in someone’s Google search to save them time.

  1. Quit App Store
  2. At the terminal: open $TMPDIR/../C/com.apple.appstore/
  3. In Finder: trash everything in that folder including any pending updates / stuck items.
  4. Relaunch App Store
  5. Done

Update: Gwynne Raskind adds: “$TMPDIR/../C is confstr(_CS_DARWIN_USER_CACHE_DIR)”.

So you’re going to teach remotely…

Remote meetings and teaching are an unfortunate necessity of the times. For those of us already using these platforms in positive ways, perhaps we can share some lessons on how to enhance your toolset.I thought I’d put together a quick post to address some of the ways things the classroom experience changes and suggest some technology support  for online classes.

I apologize for the stream of thought and incompleteness of this post. I wanted to put something out there right away. I’ll try to add, edit, and revise when time allows.

All Cameras On

I found the biggest struggle was my inability to wander through the classroom, peek over shoulders, and talk quietly to individual participants. I’m a walker and the online classroom is very much one of staying still.

My first rule is all cameras on with a further all cameras on faces. People are often uncomfortable with this, either switching their cameras off or pointing them up to the ceiling, essentially isolating themselves as students in a way they cannot do in a normal classroom, even by sitting at the very back with a phone in their lap. Push back and be insistent.

This rule goes a long way towards bringing the classroom together and making up for the fact that so much of the teaching experience is limited to a single viewpoint. The teleconferencing Zoom site offers a camera grid feature, which displays all participants at once (although not necessarily on the same screen, you will have to page through for large gatherings). This feature is especially important when you give in-class exercises, allowing you to keep track of the emotional temperature and find students who may be struggling.

Unfortunately, Zoom does provide an equivalent “screen peek”, so you cannot look over shoulders. Each screen must be shared and viewed individually.

As you teach, make sure you encourage participation, even more than you would in a normal classroom as there is always a danger of getting lost in your monotone without the immediate ability to “read the room” as you teach. Be extra conversational with give and take, much more than you would in a traditional class or seminar. This helps offset the technology and creates a warmth and inclusivity that otherwise would be missing.

Take Breaks

If you’re teaching extended classes, workshops, or labs, make sure to offer regular breaks to stretch and hit the bathroom. Put a timer onscreen. Most search engines allow you to enter “5 minute timer” and produce that timer for you automatically. Teaching, even remotely, is much more physically active a task than learning so remember your student’s endurance will be less than yours.

Prepare

Create a preflight list to ensure you’ve hit all the setup points before you go live teaching, including testing your camera and microphone and cleaning up your teaching platform. Don’t overshare. Depersonalize your desktop and your workspace.

Where possible, use a second unshared screen for teaching notes, outlines, and coordination. It’s far easier to lose track of time and go on tangents in a remote classroom because of the immediacy of the face-to-face conversation. Make sure you know what time it is, and what you have to cover in your lesson plan.

Have on hand a list of teaching objectives, scripts for live coding demos, working and starting code configurations. Don’t forget wrap-ups, next steps, and so forth. If you can, rehearse before you teach.

  • GitHub Place shareable starting source on GitHub or another publicly available site so students can follow along with minimal setup time. I use GitHub’s gist a lot.
  • Snippetty: Minimize typing with Snippetty. This menu-bar-sourced utility collects, orders, and offers the code or text snippets you’ll need during your session. Snippetty also lets you add presenter notes to those snippets. The less you type directly, the fewer typos you’ll encounter directly, and you limit long pauses during your lesson.
  • Snippety is end-of-life’d, sadly. I love this tool.

Display Tools

When displaying slides, whether from a second screen or a tablet, use the presenter notes feature to remind yourself of important topics.

A highlighting tool such as ScreenBrush (ScreenBrush for Mac and ScreenBrush for iOS) is great for circling, underlining, and drawing arrows to onscreen information.

I’m particularly fond of LargeType from Gold Mountain Software, which enables you to emphasize text or code at a readable huge size. This is a great way to call out key information. I’ve customized System Preferences > Keyboard > Shortcuts > Services > Text > LargeType to add a custom keyboard combination to perform selection enlargement without using menus. I currently have it set to Command-Control-Option-L, but you can pick whatever keyboard shortcut best works for you.

Don’t forget that your screen will be hard to read. macOS’s accessibility features enable you to use the mouse, trackpad, and keyboard to zoom parts of the screen. This allows you to zoom in on code and other important details that could be missed by showing an entire large screen. The zoom centers around your cursor by default, so it tracks your interest point and allows that field of vision to be shared with others. Visit System Preferences > Accessibility > Zoom to set your preferences

Demoing

Reflector 3 wirelessly mirrors an iOS screen, enabling you to load, launch, and demo apps from your deployment device. I also use Reflector 3 as a wireless screen-mirroring app from my iOS device.

If you don’t mind being tethered, QuickTime allows you to present your device screen for a connected iOS device.

Whiteboarding

On my iPad, I use Linea Sketchto draw. It has a present mode that hides all the normal iOS app details and just shows a plain whiteboard drawing screen. I recently upgraded to a lastest-gen iPad mini with 1st gen pencil and that has been fantastic. I also got good results before my upgrade with the rubber tipped Heiyo stylus. Use a firm stylus for writing. Most stylii are designed for drawing and to simulate brushes.  The Heiyo doesn’t scratch the screen like the metal-tipped ones, is easy to charge (microUSB), and works with older iPads.

Zoom

Zoom offers a number of great built-in features for questions, messaging, raising hands, and so forth. I particularly like using it to know when students are done with a particular task: clear the participant list and have them use a check mark or thumbs up when they have finished. This way you can continue the class without having to wait a full number of minutes.

The same tool is great for “Who thinks that X is Y” style questions. Always encourage the student to answer before looking at what others have voted.

If you can, supplement Zoom with Slack. It’s much better for creating a record of q&a (start a thread specifically for that), and for when you need to distribute text/code from teacher to students. In terms of q&a, a great approach is to allow 3-5 minutes where everyone can add their questions and then you review the questions and choose which ones you wish to answer. I got this technique from Andrew Madsen and it’s terrific. He also recommends using sli.do for audience participation.

Taking charge of those xips

Apple adopted the digitally-signed xip format for Xcode downloads a few years ago. It’s basically a signed version of zip archives. Most commonly, you download a xip and double-click. Archive Utility will open the file, verify its signature, and expand its contents.

In its default settings, Archive Utility always expands files to the same folder you download to. With Xcode, this is a big pain as moving the app with its thousands and thousands of tiny subfiles and embedded executables takes forever. Alternatively, moving the xip file from one location on your system to another can be painfully slow.

Fortunately, Archive Utility does allow you to specify where to unpack. Launch the Application using spotlight (or /System/Library/CoreServices/Applications/Archive Utility.app) and open preferences.

Although there’s no “Ask” option for “Save expanded files”, you can select where you want items to be stored using “into” from the pop-up:

Once set, you have to unset it for general use, because the location persists between launches. This is, needless to say, a big pain when you use archives for non-Xcode purposes on a regular basis:

Fortunately, you can unxip more effectively by using the command-line xip utility located in /usr/bin/xip without having to mess with Archive Utility or its preferences:

% xip
Usage: xip [options] --sign <identity> <input-file> [ <input-file> ... ] <output-xip-file>

Usage: xip --expand <input-file>

99.9% of everything you do with xip is that last “Usage” example. Still, as xip doesn’t offer a --help option, if you want to know what those interesting [options] are, you’ll need to read the man page (man xip). I prefer to open man pages in Preview instead of the command line, using this little trick:

man -t xip | open -f -a /System/Applications/Preview.app

Notice two things here:

  • First, the -t flag tells man to use the Groff typesetter (no relation) to format the page to postscript. This presents as a PDF in Preview. (Specifically, it uses /usr/bin/groff -Tps -mandoc -c if that kind of detail intrigues you.)
  • Second, the path for Preview has changed in Catalina to /System/Applications. If you want to do this on Mojave or earlier, adjust the path accordingly.

(Isn’t that a neat way to view man pages?)

While the man page suggests you can sign your own xip archives and provide your own identities, don’t bother. This format is exclusive to Apple, starting  from macOS Sierra. Only xip archives signed by Apple can be expanded in modern macOS releases. (See Tech note TN 2206 for details.)

Since --expand cannot be used with any other arguments, hop over to /Applications, and expand from there:

% cd /Applications/
% time xip --expand /Volumes/Kiku/xips/Xcode_11.2.1.xip 

Adding the time command at the start of the line lets you know how long it took to unxip, which is deeply satisfying to those of pedantic bent like myself. For those playing along, it was

xip: expanded items from "/Volumes/Kiku/xips/Xcode_11.2.1.xip"
1109.625u 275.408s 10:58.85 210.2%	0+0k 0+0io 167pf+0w

Update: