Xcode Tricks: Multiple Selection

Have you used a code text editor that’s truly sophisticated and powerful, such as SublimeText or TextMate or Visual Studio Code or RubyMine? One very cool feature that they all have in common is multiple selection, also referred to as multiple cursors.

This means you can select and edit multiple stretches of text simultaneously. When there’s a multiple selection, every character that you type is inserted in multiple places at once! This can be a tremendous time-saver, and can keep your brain from turning to mush when there’s repetitious editing to be done — as there often is when you’re coding.

But did you know that Xcode has multiple selection too? This feature achieved its current form in Xcode 10, and it’s still sitting there today, in Xcode 12, waiting for you to discover and use it. Most iOS developers, in my experience, don’t even know about this!

A Case in Point

Let me talk you through a typical situation where multiple selection might come in handy. Let’s suppose you want to use autolayout, in code, to pin a subview to its superview on all four sides, like this:

myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
myview.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
myview.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
myview.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true

That code is a royal pain to type out in the normal way.

Now, I know, I know, you’re saying: “Well, I’d never type it out in the first place. I’d use SnapKit!” (Or some other library, or an extension that makes it easy to pin a view on all four sides.)

But bear with me. Just pretend, for the sake of the example, that your only option is to type out the code in the normal way, by hand.

Without Multiple Selection

Your first step, in the normal course of things, in order to create that code by hand, is probably to type out just the first line, using code completion to help you:

myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true

That’s a template for how all the other lines are going to look, so the next thing you do is triple-click that line to select it; copy the line; and paste it, four times, to give this:

myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true

Now you go through the second, third, and fourth lines, selecting each occurrence of topAnchor and changing it. For example, you might do this:

  1. Double-click the first topAnchor in the second line to select it.

  2. Type bottomAnchor.

  3. Double-click the second topAnchor in the second line to select it.

  4. Type bottomAnchor.

  5. Double-click the first topAnchor in the third line…

And so on.

It’s not totally terrible, but it’s still a pain. It’s excruciatingly boring, and there’s a great deal of switching between the keyboard and mouse. Plus, every step feels like an invitation to make a mistake; for instance, if you don’t make the same change to both occurrences of the word topAnchor in each line, or if you accidentally make the same change to the word topAnchor in two different lines, you can end up with code that compiles perfectly well, but gives you the wrong result at runtime:

myview.leadingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true 
                                                // ^^^^^^^^^^^^^^ oops

Baby Steps

Okay, so now let’s just suppose for a moment that, in that previous line of code, you could select both occurrences of topAnchor in a given line at the same time, like this:

myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
//     ^^^^^^^^^                               ^^^^^^^^^

(The caret marks here are supposed to mean: This stretch of text is selected.) Then you could type bottomAnchor just once, and they would both be changed from topAnchor to bottomAnchor, reliably — and now you could go on to the next line.

Well, you can do that. That’s what multiple selection is all about!

In fact, you can do it in some pretty sophisticated ways. For the moment, though, let’s be content to do it in a simple “baby steps” way — because anything would be better than what we were doing before!

So follow along with me in Xcode, and try it this way:

  1. Double-click the first topAnchor in the second line to select it.

  2. Hold down the Shift and Control keys, and double-click the second topAnchor in the second line — to select it at the same time as the existing selection. Now you’ve selected two instances of topAnchor at once!

  3. Type bottomAnchor. You are typing in two places at once, so both instances of topAnchor in that line have been changed to bottomAnchor. Just what we wanted!

  4. On to the next line…

Medium Steps

So now you’re probably thinking: Hey, that was pretty cool. But you know what? The only part of the text that really needed to be edited and changed was the word top. I could be doing a lot less typing here, with a lot less chance of making a mistake, if I could select just the subword top in each occurrence of topAnchor.

Well, you can! That’s because it isn’t just typing that you can do in two places at once: also, when you make a selection within a multiple selection using just the keyboard, your keypresses operate on all of the selections at once.

Here’s an example of what I mean:

  1. Double-click the first topAnchor in the second line to select it.

  2. Hold down the Shift and Control keys, and double-click the second topAnchor in the second line to select it at the same time as the existing selection. So far, this is just like what we did before.

  3. Now: press the Left-Arrow key. Now the selection is before both instances of topAnchor.

  4. Hold down the Shift and Control keys, and press the Right-Arrow key. Now both instances of top are selected!

  5. Type bottom.

  6. On to the next line…

Giant Steps

We are still not being quite as cool as we can be. I’m not happy about all the manual Shift-Control double clicking we keep having to do.

Suppose we’ve selected the first occurrence of topAnchor in the second line. So we have already selected the very thing we now want to select another occurrence of. Wouldn’t it be great if there were a way to say: “Please select, without relinquishing the current selection, the next occurrence of the currently selected thing”? Well, there is! Here’s how:

  1. Double-click the first topAnchor in the second line to select it.

  2. Press Option-Command-E. Presto, now both instances of topAnchor in this line are selected! Okay, but now, as my mathematician father used to say, we’ve reduced it to a previously solved problem. So…

  3. Press the Left-Arrow key. Now the selection is before both instances of topAnchor.

  4. Hold down the Shift and Control keys, and press the Right-Arrow key. Now both instances of top are selected!

  5. Type bottom.

  6. On to the next line…

But wait, there’s more! One final tweak…

When we go on to the next line in step 6, we’re going to be selecting topAnchor again. So why do we have to take our hands off the keyboard and double-click with the mouse in order to do that? Why can’t we just find the next occurrence of topAnchor? Well, we can! Just press Command-G.

Summary Judgment

So, to sum up, the whole routine now goes like this. Start by typing out, in any way that is comfortable, the first line:

myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true

Select the entire line. I suggested earlier that you could do this by triple-clicking on the line; it is also possible to do it entirely from the keyboard, but let’s not get into that. Now quadruple the line by pressing Command-C followed by Command-V four times. We now have this:

myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
myview.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true

Now select, by double-clicking the first occurrence of topAnchor in the second line. That is the last double-clicking we’re going to have to do! Everything else is going to be with the keyboard alone. Okay, we’re ready to go:

  1. Option-Command-E.

  2. Left-Arrow. Shift-Control-Right-Arrow.

  3. Type bottom.

  4. Command-G. Option-Command-E.

  5. Left-Arrow. Shift-Control-Right-Arrow.

  6. Type leading.

  7. Command-G. Option-Command-E.

  8. Left-Arrow. Shift-Control-Right-Arrow.

  9. Type trailing.

Done! I think that’s pretty cool, or at least moderately cool. It’s sufficiently cool that I’ve posted a video of me doing it.

Ways of Selecting

Now that I’ve persuaded you (I hope) that making a multiple selection might be a good thing to do, here’s a summary of the various ways I know about, whereby you can make a multiple selection in Xcode:

  • Control-Shift-Click. This causes an insertion point to be added to the existing selection. You can also hold Control-Shift while doing any of the things you would normally do to form a selection. For example:

    • Double-click selects a word, so Control-Shift-Double-click selects a word and adds it to the existing selection.

    • Click-and-drag creates a selection consisting of whatever you drag over, so Control-Shift-Click-and-drag adds what you drag over to the existing selection.

  • Option-Click-and-drag. This creates a rectangular selection. The cursor will look like two crossbars at right angles to one another (like a Plus). This is useful is the specific situation where the letters you want to select are lined up in columns. For example, in the preceding code, you could select the four occurrences of myview as a rectangular selection.

  • Select any text and choose Find > Select Next Occurrence. This is the Option-Command-E shortcut that I used in my example. It makes the currently selected text the find target and does find it, but without relinquishing the current selection. You can do this repeatedly to select even more occurrences of the same text.

    If you subsequently press Command-G (Find Next), the text that was selected is still the find target, so you find the next occurrence, but you do relinquish the current selection; I did that in my example as well.

  • Choose Find > Find and Select Next (Option-Command-G) or Find > Select All Find Matches (no default key binding). This assumes that there is already a find target. This might be from doing a previous find or because you selected some text and pressed Command-E to make it the find target. There is also a variant Find > Select Find Matches in Selection.

  • Select within a symbol (meaning a word or term in your code) and choose Editor > Selection > Select All Symbols; each occurrence of that symbol is selected simultaneously. The difference between this and what I’ve been talking about up to now is that instead of looking just at a sequence of characters, it’s intelligent about what a symbol is.

    For example, if you select just the top in topAnchor and choose Select All Symbols, all occurrences of topAnchor are selected.

  • Select a stretch of code consisting of multiple lines, and choose Editor > Selection > Split Selection By Lines. The result is that instead of all the lines being selected, constituting a single selection, each line is selected, constituting a multiple selection.

Older Multiple Selection Commands

Xcode also has some older commands that create a multiple selection almost as a side effect.

For example, Editor > Edit All In Scope selects all occurrences of the currently selected term within the same scope. It is a much older command than any of the multiple selections commands I’ve talked about so far. I’m sure it existed in Xcode 4, and I have a vague memory that it is even older than that.

Also, a number of the Xcode refactoring commands involve a multiple selection in order to rename something. For instance, Editor > Refactor > Rename performs a multiple selection (in a special interface) so that you can type the new name once and apply it to all occurrences of that symbol simultaneously.

For Further Study

Keep in mind that once you have a multiple selection, you can’t manipulate an individual selection within it by using the mouse, because that will cancel the multiple selection. Therefore it’s a good idea, before using multiple selections, to be familiar with ways of manipulating a single selection using the keyboard alone.

In my example above, for instance, when the selection was topAnchor, and I wanted the selection to be just the subword top, I used Left-Arrow followed by Shift-Control-Right-Arrow. That works on a single selection when one instance of topAnchor is selected, so it works on a multiple selection when many instances of topAnchor are selected.

You can find out about lots of ways of navigating, selecting, and so forth, by looking in the Key Bindings pane of Xcode’s preferences. For instance, the Shift-Control-Right-Arrow binding is listed there as Move Subword Forward Extending Selection. (The Key Bindings pane can be difficult to understand, unfortunately, and there are a lot of bindings listed; it would be nice if there were a good online summary, but I have not found one.)

 

You Might Also Like…

Picking a Photo in iOS 14

If your app puts up an interface where the user gets to choose a photo from the photos library, you’re probably familiar with UIImagePickerController. Indeed, you’re probably all too familiar with it. UIImagePickerController is a remarkably clunky, aged piece of interface, both from the user point of view and with regard to its programming API. …

Picking a Photo in iOS 14 Read More »

    Sign Up

    Get more articles and exclusive content that takes your iOS skills to the next level.