Archive for the ‘Xcode’ Category

Xcode: Vimpocalypse Now

This has appeared at the bottom of Xcode’s Text Editing > Editing settings, sure to make many vi users very happy indeeed:

The change is heralded in the Release Notes:

Using the new vim features is super easy. When the Vim keybindings are enabled, the bottom of your source editor gets this, showing current state, plus a few reminders for those whose muscle memory isn’t quite current. It’s up to you to know your hjkluybn stuff.

You can tell if you’re navigating or editing by the shape of the cursor. The cursor is a large block when you’re navigating or using any of the commands listed here. It is a vertical pipe when directly entering text.

You can tap i to insert text, switching to text entry mode and then ESC to return to navigate. Using a colon : doesn’t do anything here, so no :wq, which is not a huge surprise as neither w nor q makes a ton of sense in Xcode.

Anyway, if your a vimficianado, congratulations and enjoy the new toy.

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.

A different way to develop SwiftPM Packages inside Xcode projects

WWDC gave us many reasons to both migrate libraries to SwiftPM and to develop new ones to support our work. The integration between Xcode development and SwiftPM dependencies keeps growing stronger and more important.

Apple’s Editing a Package Dependency as a Local Package assumes you’ll drag in your package to an Xcode project as a local package overrides one that’s imported through a normal package dependency.

In Developing a Swift Package in Tandem with an App, Apple writes, “To develop a Swift package in tandem with an app, you can leverage the behavior whereby a local package overrides a package dependency with the same name…if you release a new version of your Swift package or want to stop using the local package, remove it from the project to use the package dependency again.”

I don’t use this approach. It’s not bad or wrong, it just doesn’t fit my style.

On the other hand, opening the Package.swift file directly to develop has drawbacks in that it doesn’t fully offer Xcode’s suite of IDE support features yet.

So I’ve been working on a personal solution that best works for me. I want my package development and its tests to live separately from any specific client app outside a testbed. I need to ensure that my code will swift build and swift test properly but I also want to use Xcode’s built-in compilation and unit testing with my happy green checks.

I set out to figure out how best, at least for me, to develop Swift packages under the xcodeproj umbrella.

I first explored  swift package generate-xcodeproj. This builds an Xcode library project complete with tests and a package target. You can use the --type flag to set the package to executable, system-module, or manifest instead of the default (library) during swift package init:

Generate% swift package init
Creating library package: Generate
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/Generate/Generate.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/GenerateTests/
Creating Tests/GenerateTests/GenerateTests.swift
Creating Tests/GenerateTests/XCTestManifests.swift
Generate% swift package generate-xcodeproj
generated: ./Generate.xcodeproj

Although SwiftPM creates a .gitignore file for you as you see, it does not initialize a git repository. Also, I always end up deleting the .gitignore as I use a customized global ignore file. This is what the resulting project looks like:

As you see, the generated Xcode project has everything but a testbed for you. I really like having an on-hand testbed, whether a simple SwiftUI app or a command line utility to play with ideas. I looked into using a playground but let’s face it: too slow, too glitchy, too unreliable.

It’s a pain to add a testbed to this set-up, so I came up with a different way to build my base package environment. It’s hacky but I much prefer the outcome. Instead of generating the project, I start with a testbed project and then create my package. This approach naturally packs a sample with the package but none of that sample leaks into the package itself:

I end up with three targets: the sample app, a library built from my Sources, and my tests. The library folder you see here contains only an Info.plist and a bridging header. It otherwise builds from whatever Sources I’ve added.

I much prefer this set-up to the generate-xcodeproj approach, although it takes slightly longer to set-up. The reason for this is that SwiftPM and Xcode use different philosophies for how a project folder is structured. SwiftPM has its Sources and Tests. Xcode uses a source folder named after the project.

So I remove that folder, add a Sources group to the project, and ensure that my build phases sees and compiles those files. The Tests need similar tweaks, plus I have to add a symbolic link from Xcode’s tests name (e.g. “ProjectNameTests”) to my SwiftPM Tests folder at the top level of my project to get it to all hang together. Once I’ve done so my green checks are ready and waiting just as if I had opened the Package.swift file directly. But this time, I have all the right tools at hand.

Since I’m talking about set-up, let me add that my tasks also include setting up the README, adding a license and creating the initial change log. These are SwiftPM setup tasks that swift package init doesn’t cover the way I like. I trash .gitignore but since I have Xcode set-up to automatically initialize version control, I don’t have to git init by hand.

I suspect this is a short-term workaround as I expect the integration of SwiftPM and Xcode to continue growing over the next couple of years. Since WWDC, I’ve been particularly excited about developing, deploying, and integrating SwiftPM packages. I thought I’d share this in case it might help others. Let me know.

Importing Web-based SwiftPM packages to your Xcode Playground

I’ve been kicking the wheels on Xcode 12 and its ability to use frameworks and packages with playgrounds. Up until now, I’ve only been able to import packages that are either downloaded or developed locally on my home system. However, a lot of the packages I want to work with are hosted from GitHub.

I decided to follow a hunch and see if I could import my dependency through a local Forwarding package and then use that code. Long story short: I could.

Here’s my playground, successfully running.

The RuntimeImplementation is declared in a GitHub-hosted package called Swift-General-Utility:

What I did to make this work was that I created what I called a Forwarding Utility, whose sole job is to create a shell package that depends on the remote package and forwards it to the playground. It looks like this. It is a single file called “Forwarding.swift” (no, the name is not at all magic.) in Sources/. I use @_exported to forward the import.

/*
 
 Use this to forward web-based dependencies to Swift Pkg
 
 */

@_exported import GeneralUtility

Its Package.swift installs the dependency:

    dependencies: [ .package(url: "https://github.com/erica/Swift-General-Utility", .exact("0.0.4")), ],
    targets: [
        .target(
            name: "ForwardingUtility",
            dependencies: [ .product(name: "GeneralUtility"), ],
            path: "Sources/"
        ),
    ],

And that’s pretty much all that there is to it, other than (as I mentioned in my other post about how to use SwiftPM packages in playground workspaces) that you may have to quit and re-open the first beta before you can import the forwarding.

Let me know anything that I messed up. But also let me know if this was helpful to you!

My xcopen adventures: playground workspaces

Now that Xcode 12 supports Swift Packages for playgrounds, I thought it was time to expand xcopen to build not only playgrounds but also allow you to embed them in workspaces.

xcopen in a nutshell

If you’re not familiar with xcopen (I’ve only mentioned it briefly on this website), it’s my answer to xed. It does what xed does more or less and adds more features that I use a lot.

I built xcopen to handle command-line activities that I regularly perform during development. If you run it without arguments, it looks for a workspace and then opens that. If no workspace is found, it looks for xcode projects and playgrounds. If you pass it file names and paths, it opens those instead.

OVERVIEW: 
xcopen ...        Open files in Xcode.
xcopen docs              Open .md and .txt files.
xcopen new               Create new files (if they don't exist), open in Xcode.
xcopen xc|ws|pg(w)       Open xcodeproj, workspace, or playground.
                           * Add ios|mac|tvos to create playground.
                           * Add w (pgw) to create playground in workspace.
xcopen pkg|xpkg          Open Package.swift in TextEdit or Xcode.

USAGE: xcopen [ ...] [--background] [--folder] [--open] [--no-open]

ARGUMENTS:
                   Files to open. If blank, opens xcworkspace or,if not
                          found, searches for xcodeproj. 

OPTIONS:
  -b, -g, --background    Open Xcode in the background 
  -f, -e, --folder        Enclose new items in folder 
  --open/--no-open        Open newly created playgrounds/workspaces (default:
                          true)
  -h, --help              Show help information.

Shortcuts let you gather up your docs (like README.md, CHANGELOG.md, and LICENSE.txt) and open them together for edits.

You control whether Xcode opens in the foreground or background, enabling you to keep working without Xcode taking up your immediate attention.

Recently, I added support for playground creation. Need a Mac playground? xcopen pg mac. It emulates Finder naming  so there won’t be naming conflicts. Instead, it builds macOS, macOS 2, macOS 3, etc as your root playground names. Based on feedback from my Twitterati pals (waves hi!), I added a flag that lets you group them together in a subfolder if you don’t want multiple playgrounds cluttering your working directory.

Adding Workspaces

Today, I decided to start working with Swift packages, so I added workspace creation:

xcopen pgw mac --folder

Using pgw builds both a playground and an associated workspace. Adding --folder embeds them both into a new folder. Otherwise they are created in the working directory.

Using Swift Package Support

Add any folder containing a Swift Package to your workspace:

  • Files > Add files to workspace name (may be greyed out); or
  • Project navigator contextual pop-up > Add files to workspace name; or
  • Or just drag the folder above your playground entry in the Project navigator to ensure you’re not adding it directly to your playground.

If your package has dependencies, they’re listed in the Project navigator.

Next, try importing the new package. If it doesn’t autocomplete, quit and restart Xcode and re-open your workspace. For some reason, in this early beta it doesn’t seem to get picked up immediately.

Then test out the functionality you’ve imported. In the following example, I’m using a custom exponentiation operator:

Wrap up

I’m using xcopen a lot these days, tooling it to make my workday easier. If you find a feature you think I should include please open an issue at github. And if you like the utility, do let me know. Thanks!

The easiest way to install xcopen is via mint, which you can install with brew. Once you have mint, all you have to say is mint install erica/xcopen.

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.