Archive for the ‘Xcode’ Category

Xcode: Basics of the four-block wonder

The official name is “Navigate to Related Items” but to me, it’s the four block wonder, a menu button that sits at the top left of the Xcode editor. With this menu, you can hop between file counterparts (for example, .m/.h, or .swift/generated interface, which is what a lot of people use it for). But there’s so much more.

Set the cursor on a type, and you can view or navigate its superclass, subclasses, or siblings, as well as the protocols, extensions, and categories it connects to. A single click navigates you to the interface or implementation in question:

Use the cursor to establish the context for the menu, otherwise you’ll only see a smaller subset menu options, such as recent files. The callers option shows you your clients, and callees the items your code is calling — all specific to the current cursor context.

One of my favorite tools in the four-block menu is Generated Interfaces, which allows you to view an item’s Swift interface or see how it translates to Objective-C. For example, if you use an obvious preposition label, the ObjC generated interface subsumes it into its selector:

With this, you don’t have to wonder if your selector is specified right and you don’t have to override the selector with objc. You just look up the definition and you’re good to call.

In addition to contextual helpers, the four-block lets you select recently viewed files and, when using version control, recent files that have been locally modified and not yet committed (basically the ones showing the “M”-for-modified).

The four little squares may be tiny but it is a powerful tool in your Xcode arsenal.

Update: Lilly reminds me that you can bind the related items menu. I have mine bound to ^1 but I don’t remember if that’s something I did or something that is default. If you want to add or change, visit Preferences > Key Bindings and search for “related”.

Fun with Xcode Search Domains: Excluding match text

Most Xcode users quickly become familiar with the basics of the Find Navigator panel.

With it, you can find text, regular expressions, and perform search-and-replace, whether matching or ignoring case. But that’s just scratching the surface of the Find Navigator.

I thought I’d drop a few words today about search scopes. Controlled from the bottom left,  under the search field, you can create narrowed searches. This enables you to, for example, search only in Swift files or exclude files containing the word Test.

To get started, click the icon (two lines with three squares on a line between them) and then New Scope (the plus icon). Here, you can name the scope, limit the search extent, and add criteria for exactly which files should be included or not.

The logic is straightforward. You choose where to look (the project, a folder, or through the entire SDK), and whether to include all conditions or some conditions:

Each condition is based on the file name, path, extension, UTI (the kind of file, like image which is useful for finding vector assets), Workspace location (namely groups), or source control status (handy for finding newly applied changes.)

Most of my conditions are file-name-based. And for those, you get the following matching conditions. The “ends with” is an obvious win for extensions (although you can also use UTIs for that), and “starts with” can help for projects organized in hierarchical ways.

Now, interestingly enough, this list fails to offer “does not contain” but that’s fairly easy to work around. Since Xcode supports regex matching, you can easily replicate “does not contain” with an appropriate regex:

Change the file name to a path to exclude source file directories.

You can create as many search domains as you like. At least, I haven’t found an upper bound yet. I haven’t found a way to reorder the find scopes, although if you’re really controlling about this, you can pop into  your workspace (ProjectName.xcodeproj/project.xcworkspace/xcuserdata/username.xcuserdatad), convert your UserInterfaceState.xcuserstate to xml (plutil -convert xml1), and hand-edit it the way you need.

There are lots of wonderful little Xcode tweaks like these throughout this monster of an IDE. What are some of your faves? If I have time this week, I’ll share some of mine, such as the four-square — another of my favorite tools — and a few great ways to connect your editor to the navigator.

How I got Rust working in Xcode

A while ago, I posted about how I set up Xcode to work with Python. Yesterday, I was taking a class on Rust and decided to use my friendly neighborhood (sp)IDE(rman) coding environment, namely Xcode.

I’m not going to say it was a stunning success but there was enough interest that I thought I’d share the steps so you too could embrace Rust through Xcode.

Install Rust. You start, as one does, by installing Rust. Hop over to https://www.rust-lang.org/tools/install to grab a copy of the tools. They install to ~/.cargo, for whatever reason. I put a link in to / usr/local/bin.

Create a Project. Create an external build system Xcode project by choosing File > New > Project > Cross-platform > External Build System > Next. Enter a product name (I called mine “Rust” because that’s exactly how creative I am.) and set your build tool (in my case, /usr/local/bin/rustc because of the link). Save it somewhere convenient.

Create a source file. Apparently “rs” (rust source?) is the proper extension. I went with “test” as my name. File > New > Empty > test.rs

fn main() {
    println!("hello world");
}

Don’t forget to add some code.

Compile. Edit your scheme.  Choose Run > Info > Build Executable > Other and select your compiler. Adding it to /usr/local/bin made it easier to select rustc for me. Then uncheck Debug executable because you’re not debugging the Rust compiler.

At this point you can click Run and you’ll see the standard option message because you haven’t specified what it should run.

Back in the scheme editor select Run > Arguments and add the source file and output file. Unfortunately, I could not get this to work with SRCROOT at all, so here it is in all its glory with complete paths.

The Pre-action removes any build product from a previous run:

So here we are. With luck, it compiles. If not, the errors appear in pretty horrible form in the Xcode console, where curses is what we do, not how the console interprets pretty text output.

You can get slightly less horrible feedback by adding the launch argument: –error-format=json

Yeah, it’s wordy but it’s slightly less awful.

Pick a path. Unlike python, rust is just a compiler. If you build, and then add a step execute, the execution output (unlike compiler errors) will not normally print at the Xcode console. The challenge is to get that information in some form where you can access it.

At first I went with a little post-action osascript and threw up the output in a separate window:

But I really wanted to make it work with the console So back I went to Applescripting. Instead of rustc, I changed my build tool to osascript:

I added this instead to my run scheme arguments.

Yep, I’m using osascript to run a shell script that just compiles with rust and then runs it, passing the output through back to Xcode.

I know this is bad. I know I should be ashamed. I hang my head.

But you know what? It works. Stray osascript-crud and all:

I’m not sure how much this makes me a programming outcast but it was kind of fun to figure out how far I could push my beloved enemy Xcode.

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.