Archive for the ‘Tricks of the Trade’ Category

Pasting quoted code perfectly

You have some code you need to incorporate into a multi-line string. What’s the quickest and best way to handle it? Although I see people do this all the time, manually adding spaces to each line isn’t the best solution.

Here’s a quick Xcode tip:

  • First, paste your material into scope. Retain the indentation by using Edit > Paste and Preserve Formatting.
  • Next, if you haven’t placed them already, add the assignment and triple-quotes above and below the pasted material.
  • Select your material and use Editor > Structure > Shift-Right (Command-]) to line up the left edge of the text with the closing triple-quote. This command moves all selected material n spaces to the right, depending on how you’ve set up your tabbing. There’s a matching Shift-Left if you indent a little too much.

Hope this helps someone.

Executing command-line directly from Xcode

I got pulled into one of those conversations where I end up saying, “Fine, I’ll put up a post about it” and this is the post. Yes, you can test and run command-line apps directly from Xcode but I pretty much never do. It’s a pain with few benefits. That said, here’s how you do it.

Arguments

Let’s say you need arguments. Open your scheme (⌘<) and select the Run > Arguments tab. Add the arguments you want to pass on launch one at a time. Double-click to edit any argument:

The arguments are vended byCommandLine.arguments. Either count the array or use CommandLine.argc to find out how many arguments you’re dealing with.

print(CommandLine.arguments)
print(CommandLine.argc)

Counter-intuitively, Xcode does not automatically quote the arguments for you. This produces five arguments, not three, or six if you include the command itself:

["/Users/ericasadun/Library/Developer/Xcode/DerivedData/Test-gwehknnihlcsiucsovtbnlrdtfun/Build/Products/Debug/Test", "first", "second", "third", "fourth", "fifth"]
6

And what do you expect from the following?

You get this if you run directly in Xcode’s console:

["/Users/ericasadun/Library/Developer/Xcode/DerivedData/Test-gwehknnihlcsiucsovtbnlrdtfun/Build/Products/Debug/Test", "first", "several items at once", "third"]
4
Program ended with exit code: 0

But if you set your code to execute using Terminal:

Launching: '/Users/ericasadun/Library/Developer/Xcode/DerivedData/Test-gwehknnihlcsiucsovtbnlrdtfun/Build/Products/Debug/Test'
Working directory: '/Users/ericasadun/Library/Developer/Xcode/DerivedData/Test-gwehknnihlcsiucsovtbnlrdtfun/Build/Products/Debug'
3 arguments:
argv[0] = '/Users/ericasadun/Library/Developer/Xcode/DerivedData/Test-gwehknnihlcsiucsovtbnlrdtfun/Build/Products/Debug/Test'
argv[1] = 'first'
argv[2] = 'several'
["/Users/ericasadun/Library/Developer/Xcode/DerivedData/Test-gwehknnihlcsiucsovtbnlrdtfun/Build/Products/Debug/Test", "first", "several"]
3

Xcode’s Crazy Terminal Option

If you’re running anything with direct key input (using POSIX termios/raw mode) or curses, running in the console doesn’t work. So Xcode provides a way to run those utilities in the terminal. Visit Run > Options and scroll all the way down.

This feature is buggy as hell, produces ridiculous amounts of excess text (see this), can take a significant time to launch, and even more time for Xcode to realize the process has finished. It is impossible to use with paths that use spaces (“warning: working directory doesn't exist: '/Volumes/Kiku/Xcode/Derived'“).

I don’t like it. I don’t use it. But it exists.

Sane Command-Line Execution

Unless you’re dealing with things like automation and such, you can try out your compiled command-line apps by dragging your executable from the Products group onto the terminal. This places the path to your build at the prompt. Type out your arguments and press return:

However, I prefer to use a Copy File build phase. Select your Target > Build Phases, click plus (+) and add the executable. (I use absolute path and disable “only when installing”.) This lets you install directly to  standard locations like /usr/local/bin or ~/bin, or if you don’t want to place it there until it is stable and ready for deployment, you can use a development folder:

Assuming your destination is in your shell’s path, start a new shell for the executable to be picked up the first time. After that, you can compile and run as you like.

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)”.