Category: Tools

Renaming Xcode Projects

Renaming Xcode projects is not intuitive or obvious. If you do it wrong, you can mess up your project. In this article you will learn how to safely rename your app and your project.

Rename the Target to Rename the App

Most of the time when people want to rename their project, what they really want to do is rename their app. By renaming the app target, you can rename the app without having to rename the project.

Select the project from the project navigator to open the project editor and see a list of the app’s targets.

TargetList

To rename a target, select it, press the Return key, and enter the new name. If all you want to do is rename the app, you’re finished.

Renaming the Project

Continue reading if you really want to rename the project. If you look at the screenshot from the previous section, you might think you could rename the project by selecting it and pressing the Return key. But you’ll discover that you can’t change the project name from the project editor.

Use the project navigator to change the project name.

ChangeXcodeProjectName

Select the project file and press Return to change the name. A sheet will open.

RenameProjectSheet

Xcode is initially set to rename all the project’s targets to reflect the new name of the project. Deselect a checkbox next to any item you don’t want to rename. Click the Rename button to rename the project.

Clicking the Don’t Rename button will rename the project file but won’t rename anything else.

Xcode Breakpoint Actions

Xcode’s breakpoints pause your program so you can step through your code line by line and examine the values of your variables. But sometimes you don’t want to pause your program. You want to do something like print the value of a variable to the console. Xcode has breakpoint actions that let you do things like print a variable’s value, run debugger commands, and run scripts.

If you’re unfamiliar with Xcode breakpoints, read Introduction to Xcode’s Debugger.

Creating a Breakpoint Action

Right-click on a breakpoint in Xcode’s editor or Xcode’s breakpoint navigator (Press Cmd–8) and choose Edit Breakpoint. A popover opens to edit the breakpoint.

XcodeBreakpointEditor

Click the Add Action button to create a breakpoint action.

Breakpoint Actions

When you click the Add Action button, the popover looks similar to the following screenshot:

XcodeBreakpointActionEditor

Xcode provides the following breakpoint actions:

  • AppleScript
  • Capture GPU Frame
  • Debugger Command
  • Log Message
  • Shell Command
  • Sound

A breakpoint can have multiple actions. For example you can run a debugger command and play a sound when reaching a breakpoint.

AppleScript

The AppleScript breakpoint action runs an AppleScript script.

XcodeAppleScriptAction

Enter the script text in the text view. Most of you using the AppleScript action will write the script in a text editor and paste it into the text view. Click the Compile button to make sure the script works.

Capture GPU Frame

The Capture GPU Frame action captures a frame from the graphics card. This action helps most with apps that work with graphics, such as games, image editors, and video editing apps.

Debugger Command

The Debugger Command action runs an LLDB debugger command. The LLDB site has information on all the LLDB commands.

Enter the command in the text field.

Log Message

The Log Message breakpoint action logs a message to Xcode’s debug console. A common use of message logging is to write the value of a variable to the console. Use this action as an alternative to littering your code with print statements for debugging purposes.

Most text that you enter in the text field will appear that way in the console. Wrap variable names with the @ character. Suppose you have a game and want to display the player’s x position. The following log message:

Player X: @player.position.x@

Prints the following in the console if the x position is 12:

Player X: 12

Shell Command

The Shell Command action runs a shell script. You can use this action to run command-line programs as well as shell scripts.

XcodeShellCommandAction

Enter the command in the top text field, or click the Choose button to locate a shell script on your Mac. Enter any arguments in the bottom text field. Selecting the Wait until done checkbox tells Xcode to wait until the shell script finishes to continue.

Sound

The Sound action plays a sound. Playing a sound lets you know you hit the breakpoint. Normally you mix the Sound action with other breakpoint actions.

XcodeSoundAction

Choose a sound from the menu.

Automatically Continue

At the bottom of the breakpoint editor popover is a checkbox to automatically continue after running the breakpoint actions. If you’re using breakpoint actions, you should select the checkbox so you don’t have to click the Resume button to resume running your app.

Creating Custom Elements and Attributes in the Plot HTML Framework

Plot is a framework for creating HTML and XML documents in Swift. The Plot framework supports the most common HTML elements and attributes. But if you want to do something Plot doesn’t natively support, such as create an EPUB book, you must create custom elements and attributes. In this article I share what I’ve learned about creating custom elements and attributes.

Custom Elements

You can think of an element as a tag. Examples of HTML elements include <p> for paragraphs, <h1> for heading 1, and li for a list item. Create a custom element if there is an element you need that Plot does not have. You are more likely to create custom elements for XML than HTML.

Custom Attributes

An attribute is a value that appears inside an HTML or XML element. HTML links have a href attribute with the link destination.

<a href="https://github.com">

Like elements, you are more likely to create custom attributes for XML than HTML. Custom elements are likely to require custom attributes.

Creating a Custom Element

Call the .element function to create a custom element. There are multiple ways to call the .element function. A simple way to call it is to supply a text value for the element. The following call:

.element(named: "country", text: "Mexico")

Creates the following XML tag:

<country>Mexico</country>

You normally write a static function to create a custom element that makes a call to .element. The following function creates a custom element for a country:

static func country(_ location: String) -> Self {
    .element(named: "country", text: location)
}

Supplying Attributes

Another way to call .element is to supply a list of attributes. The following call:

.element(named: "meta", attributes: 
    [.attribute(named: "name", value: "cover"),
    .attribute(named: "content", value: "cover.png")
    ])

Creates the following tag:

<meta name="cover" content="cover.png" />

Supplying a List of Nodes

The final way to call .element is to supply a list of nodes. Supplying a list of nodes helps when creating nested tags. Normally when you have nested tags, the child nodes are nodes of a custom context.

extension XML {
    enum MyMetadataContext {}
}

static func metadata(_ nodes: Node<XML.MyMetadataContext>...) -> Self {
    .element(named: "metadata", nodes: nodes)
}

I explain custom contexts later in this article.

Another situation to supply a list of nodes is to create a custom element that includes both a text value and attributes. The following function creates a custom modified date element:

static func modifiedDate(_ dateString: String) -> Self {
    .element(named: "meta", nodes: 
        [.attribute(named: "property",  
            value:"dcterms:modified"), 
        .text(dateString)
        ])
}

Calling modifiedDate creates an element that looks like the following:

<meta property="dcterms:modified">2020-04-03</meta>

The exact value depends on the date string.

Creating a Custom Attribute

Call the .attribute function to create a custom attribute. Supply the name of the attribute and its value. The following call:

.attribute(named: "xml:lang", value: "en")

Creates the following attribute:

xml:lang="en"

Like with custom elements, you normally write a static function to create a custom attribute. The following function creates a custom attribute for the language of an XML document:

static func xmlLang(_ language: String) -> Self {
    .attribute(named: "xml:lang", value: language)
}

Example: Create a Spine for an EPUB Book

Now it’s time for a real example, creating the spine for an EPUB book. The spine contains a list of files in the order they appear in the book. The following code shows the XML of a sample spine:

<spine toc="ncx">
    <itemref idref="Chapter1"/>
    <itemref idref="Chapter2"/>
    <itemref idref="Chapter3"/>
    <itemref idref="Chapter4"/>
    <itemref idref="Chapter5"/>
</spine>

Building the spine in Plot requires two custom elements: one for the spine and one for the item references. The spine element requires a custom attribute for the table of contents (toc). The item reference element requires a custom attribute for the ID reference.

Create New Contexts

A context is a section of an HTML or XML document where elements and attributes reside. Plot has a BodyContext for HTML documents that corresponds to the <body> tag in the document. Most HTML elements reside in the body context.

Custom attributes usually require you to create a custom context. Sometimes custom elements also require a custom context.

To create the spine, create new XML contexts for the spine and spine item.

extension XML {
    enum SpineContext {}
    enum SpineItemContext {}
}

The SpineContext context contains anything inside a <spine> tag, which is going to be the spine items and the spine element’s custom attribute. The SpineItemContext context contains anything inside an <itemref> tag, which is each item’s ID reference.

Create the Spine Custom Element

The next step is to create the spine custom element, which you can see in the following code:

extension Node where Context == XML.DocumentContext {
    static func spine(_ nodes: Node<XML.SpineContext>...) -> Self {
        .element(named: "spine", nodes: nodes)
    }
}

The code creates an element named spine with a list of child nodes. The child nodes include the spine’s custom attributes and the item reference elements. The child nodes must be in the spine context.

Create the Spine Custom Attribute

Now let’s create the spine’s custom attribute, which you can see in the following code:

extension Node where Context == XML.SpineContext {
    static func spineTOC() -> Self {
        .attribute(named: "toc", value: "ncx")
    }
}

Notice the class extension for the spineTOC function applies to the spine context so the attribute appears inside the spine tag.

Create the Item Reference Element

The next task is to write the code to create the item reference element.

extension Node where Context == XML.SpineContext {
    static func item(_ nodes: Node<XML.SpineItemContext>...) -> Self {
        .element(named: "itemref", nodes: nodes)
    }
}

The item function must be inside the spine context for the item reference elements to appear inside the spine tag.

The nodes are going to be the ID references.

Create the ID Reference Attribute

There’s one more custom attribute to write, the item’s ID reference.

extension Node where Context == XML.SpineItemContext {
    static func itemID(_ name: String) -> Self {
        .attribute(named: "idref", value: name)
    }
}

The itemID function must be inside the spine item context for the attributes to appear inside the item reference tag.

Creating the Spine

The last step is to write a function to build the spine using the custom elements and attributes. Assume there is a Book struct that contains a list of chapters. Each chapter has a title.

func buildSpine() -> Node<XML.DocumentContext> {
    let spine = Node.spine(
        .spineTOC(),
        .forEach(chapters) {
            .item(Node.itemID($0.title))
        })

    return spine
}

The first line of code in the buildSpine function creates the spine custom element. The second line creates the spine element’s custom attribute.

For each chapter in the book, the code creates a spine item custom element and an item ID (idref) custom attribute for the spine item. The item ID’s value is the chapter’s title.

Once you do the work of writing functions for the custom elements and attributes, it doesn’t take much code to do something like build the spine for an EPUB book.

Cherry Picking a Git Commit in Xcode

Xcode 11 adds support for cherry picking commits. Cherry picking involves taking a commit from one git branch and applying it to another branch. Cherry picking lets you apply a commit to a branch without having to merge all your recent commits into that branch.

Take the following steps to cherry pick a commit in Xcode.

  1. Open the source control navigator by pressing Cmd–2.
  2. Checkout the destination branch, the branch that will receive the cherry picked commit.
  3. Select the branch with the commit to cherry pick. Xcode’s editor will show all the commits for that branch.
  4. Select the commit.
  5. Right-click and choose Cherry-Pick.
  6. An alert will open asking if you want to cherry pick. Click the Cherry-Pick button.

Want to Learn More About Version Control?

I wrote a book about it.

Accessing the SwiftUI Views Library in Xcode

Are you running macOS 10.15 and trying to build a SwiftUI user interface visually? Are you having trouble finding the SwiftUI user interface elements, the SwiftUI equivalent of Xcode’s object library for storyboards?

When you click the Add button in the toolbar, Xcode shows the code snippets library instead of the view library. You must click the View Library button in the library window to access the SwiftUI views.

SwiftUIViewsLibrary

The View Library button is the left button in the group of five buttons in the screenshot. The canvas must be open for the View Library button to appear in the library window. Once you have access to the view library, you can drag views to the canvas and build your interface visually.

Xcode 11 Missing View Controllers

I have seen a lot of questions recently from people who are creating iOS projects in Xcode 11 and not being able to find the ViewController.swift file and not being able to find view controllers. Usually these questions come from people who are following a tutorial written with an earlier version of Xcode.

The cause of the issue is that Xcode 11 defaults to using SwiftUI for new iOS and Mac projects.

Xcode11UserInterfaceMenu

SwiftUI is a new framework from Apple for making user interfaces for Apple devices. SwiftUI does not use view controllers so when you create a SwiftUI project, there aren’t going to be any view controllers in the project.

The solution to the issue is to choose Storyboard from the User Interface menu when you create the project. When you tell Xcode to use storyboards for the user interface, your project will include a view controller and a ViewController.swift file.

Introducing the Swift Package Manager

Xcode 11’s improved support for the Swift Package Manager simplifies adding and updating third party frameworks in your projects. In this article you’ll learn how to use the Swift Package Manager to add third party frameworks to your apps.

Accessing the Swift Packages

You can access the Swift packages by selecting your project from the project navigator and clicking the Swift Packages button at the top of the project editor.

SwiftPackagesList

Initially the list of Swift packages is empty.

Adding a Swift Package to Your Project

Click the Add button to add a package to your project. Enter the name of the package or the URL of the package repository in the search field. You’ll get more accurate results if you know the repository URL. The following screenshot shows a search for the SwiftCheck testing library:

ChoosePackageStep1

After choosing the package to add, click the Next button.

Specifying Version Rules

The next step is to specify the rules for what version of the package to use. You can choose a version, a branch from the git repository, or a specific git commit. Most of the time, you’ll either use a version or a branch. Using the master branch would ensure you’re using the latest stable version.

Xcode provides four different version rules.

  • Up to next major. If the current version of the package is 1.1, it will use the latest 1.x version. It won’t use version 2 of the package.
  • Up to next minor. If the current version of the package is 1.1, it will use the latest 1.1.x version. It won’t use version 1.2 of the package.
  • Range, which lets you specify the version ranges of the package to use.
  • Exact, which uses a specific version of the package.

Xcode defaults to using up to next major. Click the Next button. Xcode will generate the package for you. Click the Finish button.

Viewing the Dependencies

After adding a Swift package to your project, the project navigator will show the Swift package dependencies.

SwiftPackageDependencies

Adding the SwiftCheck package dependency to the project also adds the packages SwiftCheck depends on: FileCheck, llbuild, SwiftPM, and Rainbow. Xcode added the dependencies without me having to do anything. Now I can import the SwiftCheck module into my unit testing classes and use SwiftCheck to generate test cases for me.

Changing a Rule

Suppose you made a mistake specifying a version rule when you added a Swift package to your project. How do you change the rule?

Access the list of Swift packages in your project from the project editor. Double-click on the package to open a sheet to change the rule.

SwiftPackageChangeRule

An Introduction to Xcode’s Debugger

I see a lot of questions on forums from iOS and Mac developers having issues with their code not working properly or crashing with cryptic error messages, like the following:

  • Thread 1: signal SIGABRT
  • Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
  • EXC_CRASH (SIGTRAP)
  • Unrecognized selector sent to instance
  • Thread 1: EXC_BAD_ACCESS (code=2, address=0x102044190)

Many of these issues can be fixed quickly with the help of Xcode’s debugger. In this article I will show you the basics of Xcode’s debugger so you can find and fix bugs in your code more quickly.

Breakpoints

Breakpoints are fundamental to using debuggers. Breakpoints pause your app so you can debug it. If you want to debug an Xcode project, you will have to set at least one breakpoint.

Setting Breakpoints

The easiest way to set a breakpoint is to click on the left side of Xcode’s editor next to the line of code where you want your app to pause.

EnabledBreakpoint

The blue arrow in the editor indicates a set breakpoint.

Disabling Breakpoints

Suppose you set a breakpoint inside the loop. You don’t want your app to pause every time you go through the loop. By disabling the breakpoint after going through the loop once, Xcode won’t pause at the breakpoint until you enable it.

Click on an enabled breakpoint to disable it.

DisabledBreakpoint

Setting an Exception Breakpoint

Setting a breakpoint on a line of code works when you have an idea of where the problem is in your code. But if your app is crashing, it can be tough to find the source of the crash in your code.

Finding the source of crashes is where exception breakpoints come in. When your app crashes, it throws an exception. Setting an exception breakpoint pauses execution of your app when it crashes so you can locate the source of the crash.

To create an exception breakpoint, choose Debug > Breakpoints > Create Exception Breakpoint. A popover opens.

ExceptionBreakpointPopover

You shouldn’t have to change anything in the popover. Make sure the Exception menu is set to All and the Break menu is set to break on throw.

You can find more information on the common causes of app crashes in the Fixing and Avoiding Crashes in Swift Code article on this site.

Debug Area

Now that you set some breakpoints, you can build and run your project. When your app reaches a breakpoint, Xcode pauses the app, showing the debug area of the project window at the bottom of the window.

DebugAreaHighlighted

As you can see in the screenshot, there are three sections of the debug area.

  • Debug bar
  • Variables view
  • Console

Debug Bar

The debug bar contains buttons to perform the most common debugging commands. There are two sets of buttons divided by a thin vertical separator. The first set has the following buttons, running from left to right:

  • Show/hide the debug area
  • Activate/deactivate breakpoints, which allows you to quickly toggle your active breakpoints with one click.
  • Resume program execution
  • Step over
  • Step into
  • Step out

The second set has the following buttons:

  • Debug view hierarchy
  • Debug memory graph
  • Override appearance
  • Simulate location

The buttons in the second set are beyond the scope of this article. Debugging the view hierarchy and debugging the memory graph could be the subject of their own articles.

Stepping

In the previous section you saw that the debug bar has three buttons for stepping through your code: step over, step into, and step out. When should you step over, step into, and step out?

You are going to step over code the most. When you step over a line of code, the debugger executes that line of code and moves to the next line. Unless the current line of code calls another function, you should step over that line.

If the current line of code calls another function, you may want to step into the function. Suppose you have a function A that calls function B. If you step over the call to B, the debugger goes through all the code in B and takes you to the next line in A. This behavior may be what you want, especially if you are making a call to a function in Apple’s frameworks, where you don’t have the source code.

But you may want to step through the code in B. To step through the code in B, step into the call to B in function A. The debugger will take you to the start of B, where you can step over the code in B line by line.

When you step into a function, you can use the Step Out button to go back to the previous function. If you are in B and want to go back to A, click the Step Out button.

Variables View

The variables view shows your app’s variables and their values. Sometimes it can be tough to find the value you want in the variables view. The variable you want may be nested inside data structures. The value may show up as a memory address instead of the real value. When the variables view doesn’t show what you want, you must resort to the console.

Console

The console shows any messages your app generates as it runs. If you have any print statements in your code, the printed messages will appear in the console.

You can also use the console to run LLDB debugger commands. The LLDB page has a list of commands.

One common command is the po command that prints out the contents of a variable. If you type a variable name, you’ll notice the console supports Xcode’s autocompletion.

Adding Folders of Files to Xcode Projects

When you add a folder of files to an Xcode project by choosing File > Add Files to “ProjectName”, you should see the following options at the bottom of the Open panel:

Xcode10AddFolders

As you can see there are two options for adding folders to a project.

  • Create groups
  • Create folder references

What’s the difference between creating groups and folder references?

When you create a group for a folder, Xcode creates a yellow folder for the folder in the project navigator. Create a group when you need to edit the folder’s files in Xcode. If you’re adding a folder of source code files, you should create a group for the folder.

When you create a folder reference, Xcode creates a blue folder in the project navigator. The folder will also be copied to the app bundle when you build the project. Create a folder reference when you don’t need to edit the folder’s files in Xcode. If you’re adding a folder of image or sound files, you should create a folder reference.

Finding the Slow Spots in Your Code with the Time Profiler Instrument

I continue my coverage of Instruments with the Time Profiler instrument. If your app is running slowly, use the Time Profiler instrument to find the slow spots in your code so you know where to optimize.

If you are new to Instruments, I recommend reading the Measuring Your App’s Memory Usage with Instruments article. That article provides an introduction to Instruments and covers some aspects of using Instruments this article glosses over.

How the Time Profiler Instrument Works

The Time Profiler instrument records the call stack every millisecond. The function at the top of the call stack is the function your app is currently executing. If a function appears at the top of the call stack in a lot of samples, that’s a sign your app is spending a lot of time in that function.

Launch and Record

Choose Product > Profile in Xcode to launch Instruments. Select the Time Profiler template and click the Choose button.

Click the Record button to launch your app and start profiling.

Controlling the Graph

When you pause recording you’ll notice the Time Profiler instrument shows a lot of graphs. There’s a graph for each thread, and iOS and Mac apps have a surprisingly high number of threads.

Above the graph is a series of buttons to control what graphs appear in the trace document window.

GraphFilter

You can show instruments, threads, or CPU cores. You can also use the search field to filter what graphs appear. At the start you should focus on instruments, specifically CPU usage, because it helps find the slow spots in your code.

CPU Usage Graph

Starting with Xcode 10 the Time Profiler instrument has two graphs: CPU usage and life cycle. If you move the mouse cursor over the CPU usage graph, tooltips appear with the percentage of CPU usage at that moment in the recording.

Life Cycle Graph

The life cycle graph reports the current state of your app: initializing, launching, foreground, or background. If you move the mouse over the life cycle graph, tooltips tell you the state of the app and the amount of time the app was in that state.

Older versions of Xcode do not have a life cycle graph.

Profile Data

The Time Profiler instrument shows the call tree view initially. Click the Call Tree button at the bottom of the window and select the Invert Call Tree and Hide System Libraries checkboxes to make your code easier to find in the call tree view.

CallTree

For each function the call tree tells you its weight and it self weight. The weight is expressed as a time and a percentage. The weight measures the amount of time the function was on the call stack. The self weight measures the amount of time the function was at the top of the call stack.

The Self Weight column is more important. Suppose you have a function A that calls functions B and C. The Weight column for A tells you the amount of time your app was in functions A, B, and C. The Self Weight column for A tells you the amount of time your app was in A. When you’re looking for the slow spots in your code, look at functions with a high self weight.

Double-clicking a function opens the source view, where you can see the lines of code that take the most time in the function.

Narrative

The narrative section has a listing for each event in the Life Cycle graph. Each listing has the start time relative to the start of the recording and a description of what the app is doing.

Older versions of Xcode do not have a narrative section.

Samples

If you choose Samples from the jump bar, you can look at every sample the Time Profiler instrument took during the recording. Instruments shows the following data for each sample:

  • Sample time, relative to the start of recording
  • Core, the CPU core
  • Process, which is the name of your app
  • Thread
  • State, which is usually Running
  • Backtrace, which lists the function at the top of the call stack

The extended detail view shows a compressed backtrace. If you want to see every function in the call stack, click the button at the top right of the backtrace.

ExpandBacktraceHighlighted

Remember that the Time Profiler instrument takes a sample every millisecond so there are a lot of samples to go through.

CPU Cores

If you move the mouse cursor over a CPU core in the graph, a tooltip appears showing you the percentage of CPU usage for that core at that moment in the recording.

Selecting a CPU core from the instrument list fills the detail view with call tree statistics for that core. Choosing Samples from the jump bar shows all the samples Instruments recorded for that CPU core.

Threads

If you move the mouse cursor over a thread in the graph, a tooltip appears showing the percentage of CPU usage for that thread at that moment in the recording. The graph can tell you if the main thread is doing too much work.

Selecting a thread from the instrument list fills the detail view with call tree statistics for that thread. Choosing Samples from the jump bar shows all the samples Instruments recorded for that thread.

Summary

The main point of using the Time Profiler instrument is to find the slow spots in your code. Look for functions in the call tree with a high self weight. If you need to make your app run faster, start by optimizing those functions with a high self weight.