Category: SwiftUI

Accessing the Document in a SwiftUI Menu

You’re making a SwiftUI document-based Mac app. You have a menu item in your app that performs an action on the document. How do you give the menu access to the document?

Use focused values and focused bindings.

Creating a Focused Value

A focused value provides a way for a SwiftUI app to observe values from the focused view or one of its ancestors. In a document-based SwiftUI Mac app, one of the focused view’s ancestors is the document window. By using a focused value your app can access the focused document.

To create a focused value, you must write two pieces of code. The first is a struct that conforms to the FocusedValueKey protocol. The second is a property for the document as an extension to the FocusedValues struct.

The struct creates a type alias for the document’s type, which is usually a binding to your document type.

The document variable is the value you will use when setting the focused value. The value must match this variable name.

Notice the type of the variable, DocumentFocusedValueKey.Value?. The first part of the type is the name of the struct you created for the focused value. The second part is the name of the type alias you created in the struct.

Setting a Focused Value

The .focusedValue modifier sets a focused value.

The name of the first argument must match the name of the variable you created in the FocusedValues extension.

Apple added the .focusedSceneValue modifier in iOS 15 and macOS 12. This modifier works much better than .focusedValue, which requires the person using the app to be focused on a text view or text field. If you can require iOS 15 and/or macOS 12, use .focusedSceneValue.

Where do you place the code to set the focused value? Attaching the focused value modifier to the content view in the app file is the most common place in a document-based SwiftUI app.

Focused Bindings

A focused binding gives a SwiftUI view access to the focused value. To create a focused binding, declare a variable with the @FocusedBinding property wrapper and supply the name of the focused value in parentheses.

Using Focused Bindings in SwiftUI Menus

To use a focused binding in a SwiftUI menu, you must create a SwiftUI view for the menu items. Create the menu items in the group. The following example shows a menu with items to make text bold and italic:

Creating Menu Commands

If you have a menu with multiple menu items, creating a set of menu commands lets you keep the menu creation code in its own Swift file. To create a set of menu commands, supply the views inside the CommandMenu block.

Add the Menu to the App

The final step is to add the menu to the app.

By creating a struct for the menu commands, the code inside the app’s body is much cleaner.

Credits

I learned much of the information shared in this article from the following article by Lost Moa:

Accessing the document in the SwiftUI macOS menu commands

Using a Scrollable Text View in a Mac SwiftUI App

In the article Using Text Views in a SwiftUI App I showed how to use a UIKit text view in a SwiftUI app. But if you use the code from that article in a Mac app, you’ll run into a problem. The text view won’t scroll when you reach the bottom of the text view. In this article you’ll learn how to make the text view scroll in a Mac app.

Much of the code for this article comes from the CodeEditor Swift package, which is a text editor for SwiftUI with syntax highlighting.

Create a Scroll View

The reason the text view won’t scroll is that Mac text views aren’t wrapped in scroll views like iOS text views are. When you create the text view, you have to create both a text view and a scroll view. Set the scroll view’s document view to the text view. Give the scroll view a vertical scroller. Return the scroll view.

Setting the autoresizing mask ensures the text view resizes properly when the window resizes.

Updating the View

When writing the updateNSView function, supply the scroll view as the argument. Use the documentView property of the scroll view to access the text view and update its contents.

Removing Items from SwiftUI Lists in Mac Apps

Most examples of removing items from SwiftUI lists use the .onDelete handler, which is not available for Mac apps. In this article I share what I learned to remove list items from SwiftUI Mac apps.

To remove items from SwiftUI lists in Mac apps, you must perform the following tasks:

  • Add a variable to the list view to store the selected list item.
  • If you are using a navigation link, supply a tag and selection when creating the link.
  • Make your struct or class conform to the Equatable and Hashable protocols.
  • Add the .onDeleteCommand handler to the list. The .onDeleteCommand handler is the handler SwiftUI Mac apps use to remove list items.

Add a Selection Variable to the List View

To remove an item from a SwiftUI list, the list view requires a variable to store the item you want to remove. Create an optional for the variable and set it to nil initially.

ListItemStruct is the name of the data structure in your app that you want to show in the list.

When you supply this selection when creating a navigation link, SwiftUI keeps track of the selected item in the list.

Most SwiftUI apps that use lists use a navigation link to create master-detail interfaces. Select an item from the list to show additional information in the detail view. Add a call to NavigationLink in the master view and set its destination to the detail view.

To support more complex selection behavior, you must supply two additional arguments to the navigation link call: tag and selection. Usually the tag is the current list item you’re adding to the list. The selection is the variable you added to the list view.

The following code demonstrates how to show a list of a book’s chapters:

This example uses the improved syntax Apple added in Xcode 13 to bind list text fields to items in an array. If you’re using Xcode 12 you will have to use a Text to display the titles and remove the $ character from $chapter.

Make Your Struct/Class Conform to Equatable and Hashable Protocols

To use the tag and selection arguments in a navigation link, your struct or class must conform to the Equatable and Hashable protocols. Your project won’t compile until you make the struct or class conform to those protocols.

Making your struct or class conform to Equatable requires you to implement the == operator to check for equality.

Replace Chapter with the name of your struct or class. Do whatever comparisons you need to make to determine that two objects are equal. SwiftUI list items require a unique ID. That’s what I used to determine equality in the example.

To conform to the Hashable protocol, you must implement the hash function.

Inside the hash function, call the hasher’s combine function for each property in your struct or class. Supply the name of the property.

Add the .onDeleteCommand Handler to the List

The last step is to remove the item from the list. Add the .onDeleteCommand handler to the list to enable the Delete menu item in the Edit menu. Inside the block of code, you will use the selection variable you added to the list view to find the selection index. Use the selection index to remove the item from the list.

The firstIndex function returns the first selected item in the list. After getting the index of the selected item, remove that item from the array that populates the list.

Now let’s put the whole list view together.

Removing an Item with a Button and the Delete Key

At this point you can remove a list item by choosing Edit > Delete. But you may want to provide a button to remove an item. How do you remove list items by clicking a button?

Start by moving the code inside the .onDeleteCommand handler into its own function. Moving the deletion code into a separate function will also make the list code cleaner.

Now the .onDeleteCommand handler looks like the following:

Call the function in your button. Add a .keyboardShortcut handler to the button to remove list items with the Delete (Backspace) key.

I haven’t figured out how to add a keyboard shortcut for the Delete menu item in the Edit menu. Every example I’ve seen on creating keyboard shortcuts for menu items in SwiftUI uses custom menu items, not the menu items that Apple supplies. I’ll update the article if I ever find a solution.

Sample Project

I don’t currently have a sample project to demonstrate list item removal. If you want to see an example of a SwiftUI Mac app that lets you remove items from a list, take a look at the Feed Read example by TrozWare.

Should I learn Swift or SwiftUI?

I see a lot of new iOS developers ask the question in the title of this article. The short answer is both. To write SwiftUI apps you must also learn Swift because Swift is the programming language SwiftUI uses. The rest of this article provides a more detailed explanation.

UIKit

In 2008 Apple gave developers a SDK (Software Development Kit) to let them make native iOS apps. The heart of the SDK was UIKit, a framework for creating the views and controls in iOS apps, such as buttons, text fields, and table views.

UIKit uses the Objective-C programming language. Using Objective-C worked well for existing Mac developers, who were already using Objective-C to make Mac apps. But the release of the iOS SDK attracted lots of new developers to the Apple developer community. These new developers found Objective-C’s syntax to look strange and found it difficult to understand. They wanted a language with a syntax that looked more familiar.

Swift

In 2014 Apple unveiled their solution for developers who hated Objective-C: the Swift programming language. Swift’s syntax looked more familiar to people who came to iOS development from web development and Windows development. Now iOS developers had two language choices for making iOS apps with UIKit: Swift and Objective-C.

SwiftUI

In 2019 Apple released the initial version of SwiftUI, a new framework for developing apps for all of Apple platforms: iOS, Mac, tvOS, and watchOS. SwiftUI has only one language: Swift. You must know Swift to use SwiftUI.

The Language and Framework Options for iOS Apps

Someone who wants to make iOS apps with Apple’s frameworks has three options.

  1. Use UIKit with Objective-C.
  2. Use UIKit with Swift.
  3. Use SwiftUI with Swift.

Which option should use choose? You won’t be making a mistake no matter which option you choose. But for someone new to iOS development, I recommend Option 3, write the app with SwiftUI using Swift. SwiftUI is the future of iOS development. You’re eventually going to have to learn it so you might as well learn it now.

Make a Markdown Editor in SwiftUI

In this tutorial you will make a Markdown editor with live preview using SwiftUI. This editor will run on both iOS and Mac. It’s a nice example to demonstrate how to create a document-based, multi-platform SwiftUI app. Plus, it shows how to use a WebKit web view in SwiftUI.

This tutorial uses the new document-based app features Apple added in Xcode 12. You must be running Xcode 12.2+ to create a multi-platform SwiftUI app. The iOS app requires iOS 14+, and the Mac app requires macOS 11+. If you are running macOS 10.15 (Catalina) on your Mac, you can still make the editor. You won’t be able to run the Mac version.

To keep the tutorial from getting too long, I will gloss over some steps and explanations that I covered in the following articles:

Create the Project

Start by creating the project.

  1. Choose File > New > Project in Xcode.
  2. Click the Multiplatform button at the top of the New Project Assistant.
  3. Choose Document App from the list of application templates.
  4. Click the Next button.
  5. Name the project in the Product Name text field.
  6. Click the Next button.
  7. Choose a location to save the project.
  8. Click the Create button.

If you look at the project navigator, you will see Xcode creates the following folders for your project:

  • The Shared folder contains files that both the iOS and Mac app targets use.
  • The iOS folder contains files that the iOS app uses.
  • The Mac folder contains files that the Mac app uses.

In the Shared folder are Swift files for the app, document, and content view.

Run the project and you will see that you have a working plain text editor. You can create documents, edit text, save documents, and load documents.

Add the Ink Package

This project uses the Ink Markdown parser to convert the Markdown you type in the text editor to HTML that you will preview. Ink has Swift Package Manager support to simplify adding it to your Xcode project.

Select the name of your project from the project navigator to open the project editor. Select the project from the project editor and click the Swift Packages button at the top of the editor to add the Ink package.

A current limitation in Xcode’s Swift Package Manager support is you can add a package to only one target initially. To add Ink to the other app target, select the target from the project editor and add the Ink framework from the Frameworks, Libraries, and Embedded Content section.

AddSwiftPackageToSecondTarget

Add Web Views

To preview the Markdown you write, you need a web view to display the HTML. SwiftUI does not currently have a native web view so you must use a WebKit web view, WKWebView, for the preview.

WKWebView has both iOS and Mac support, but you’re going to have to create two web view files: one for the iOS app and one for the Mac app. The code is going to be almost identical. The reason you need two files is that SwiftUI has separate protocols for working with UIKit(iOS) and AppKit(Mac) views.

Create one new Swift file in the iOS folder in the project navigator and create a second file in the Mac folder. Make sure the file in the iOS folder is a member of the iOS app target. Make sure the file in the Mac folder is a member of the Mac app target. You can set the target membership for a file using the File Inspector on the right side of the project window.

Add the following code to the iOS Swift file:

The web view uses the SwiftUI and WebKit frameworks so you must import them. When you use a UIKit view in a SwiftUI app, the view must conform to the UIViewRepresentable protocol. The html property stores the HTML to display in the web view.

There are three functions. The init function initializes the web view with some HTML to display. The makeUIView function creates the web view. The updateUIView function loads the HTML string to show in the web view.

The Mac code is almost identical. Replace anything starting with UI with NS.

Parsing the Markdown

The next step is to write some code to parse the Markdown to HTML. Open the ContentView.swift file. Import the Ink framework.

Add the following computed property to the ContentView struct:

This code creates an Ink parser and calls a function that converts the document text into HTML. This code is much easier to write than creating your own Markdown parser.

Build the User Interface

The last step is to build the user interface. The user interface contains a text editor and a web view side by side.

The body property for the content view should look like the following code:

The code creates a horizontal stack so the text editor and web view are side by side. The text editor is on the left and contains the document’s text. The web view is on the right and displays the HTML you parsed from the Markdown text. The iOS app uses the iOS version of the web view. The Mac app uses the Mac version of the web view.

Run the project. Any Markdown you type in the text editor will appear as HTML in the web view. The Ink parser does not currently support creating code blocks with indentation. You must add three backticks on the line above and below the code to create a code block.

I have the project on GitHub for you to look at if you run into problems.

Creating Document-Based Apps with SwiftUI

Xcode 12 Note from the Author

Xcode 12 made a bunch of changes to SwiftUI for document-based apps. If you choose a multi-platform document app project, you will get the text editor project I create in this article without having to write any code. I’m keeping this article up for people who are still using Xcode 11.

The article Make a Markdown Editor in SwiftUI shows how to create a document-based SwiftUI app with Xcode 12.

Start of Original Article

I have not seen any articles or tutorials on creating a document-based app with SwiftUI so I’m writing one. In this tutorial you will build an iOS plain text editor.

If you haven’t already, I recommend reading two articles before going through the tutorial. Creating Document-Based iOS Apps Part 1 provides an overview of creating document-based iOS apps. Using Text Views in a SwiftUI App provides an explanation of using a UIKit text view in a SwiftUI app. SwiftUI does not currently have a built-in text view.

Create the Project

Start by creating a project. Create an iOS document-based app project. Choose SwiftUI from the User Interface menu if it’s not already selected.

The most interesting files Xcode creates for a document-based SwiftUI app are the following:

  • DocumentBrowserViewController.swift contains code for the document browser, where people create and open documents.
  • DocumentView.Swift contains code for the document’s main view.
  • Document.Swift contains code for the document.

Creating a New Document

If you run the project, you’ll notice that tapping the Create Document button does nothing. You must write some code to create the document when someone taps the button. The easiest way to create a new document is to add an empty file to the project. The empty file should have the same file extension as the document’s. This file will be copied to the app bundle when building the project. You’ll have to write some code to load the file from the app bundle.

One last thing to do to create documents properly is to configure the document type in Xcode so that the app is an editor of plain text files.

Add an Empty Document File

Choose File > New > File to add a new file to the project. Select Empty from the list of iOS file templates. The empty file is in the Other section. You have to scroll down a bit to reach the Other section.

Name the file. I named the file New Document.txt. You can choose a different name, but remember the name.

Load the Empty Document

Open the DocumentBrowserViewController.swift file and go to the didRequestDocumentCreationWithHandler function. Replace the following line of code:

With the following code:

This code loads the empty document file from the app bundle and uses that as the base for a new document.

There is one more piece of code to change. In the same function, find the following code:

There is a problem with the code inside the if block.

This line of code moves the file from the application bundle. Your app will crash the second time you create a document because the empty document file was moved out of the application bundle. The fix is to copy the file from the application bundle when creating a new document.

Edit the Document Type

Xcode initially sets the document type for an iOS document-based app to be a viewer of image files. You must configure the document type in Xcode so that the app is an editor of plain text files. You’re making a text editor, not a text viewer.

Select the project from the project navigator to open the project editor. Select the app target from the left side of the project editor. Click the Info button at the top of the project editor to access the document types. Click the disclosure triangle next to Document Types.

DocumentTypes

  1. Enter PlainText in the Name text field.
  2. Enter public.plain-text in the Types text field. public.plain-text is the UTI (Uniform Type Identifier) for plain text files.
  3. In the Additional document type properties section, set the CFBundleTypeRole value to Editor so people can edit documents.
  4. Set the LSHandlerRank value to Alternate to ensure this text editor isn’t the default text editor for all plain text files.

Create the Data Model

The data model for this project is simple. The document is the data model. All you have to do is add a property to store the text. Open the Document.swift file and add the following code inside the Document class:

The code declares a property to store the text and has the initial value of an empty string.

Building the Text View

Now it’s time to add the text view so people can edit text. Currently SwiftUI does not include a text view so you have to write code to create a UIKit text view. But it’s not too much code. Add a new Swift file to your project for the text view. Import the SwiftUI and UIKit frameworks. Add the following struct:

The text view must conform to the UIViewRepresentable protocol, which is the protocol that allows the use of UIKit views in SwiftUI apps. To conform to the protocol, you must write the following functions:

  • makeUIView
  • updateUIView
  • makeCoordinator

The makeUIView function creates and configures the view. The function takes an argument of type Context and returns the type of view you want to make, which is UITextView for a text view. The Context type is a type alias for the context where updates to the UIKit view take place.

The code listing creates a text view, configures the view so people can edit large amounts of text, and adds some padding so the text isn’t on the left edge of the screen. The code also sets the view’s delegate to the context’s coordinator, which you will create shortly.

The updateUIView function handles updates to the view.

I will fill in this function later.

The makeCoordinator function creates a coordinator so the UIKit view can communicate with data in SwiftUI.

Create the Coordinator

Add a Coordinator class inside the struct for the text view.

The class inherits from NSObject, which is the base class for all UIKit classes. A text view’s coordinator should conform to the UITextViewDelegate protocol so it can respond to text view notifications, such as the text changing.

The coordinator needs a property to hold the UIKit view and an initializer. I will be adding more to the coordinator later in the article.

Add the Text View to the Document View

The last step to adding the text view is to have the document view display it. Open the DocumentView.Swift file. Inside the body property you should see a VStack that contains a HStack and a button. The HStack shows the name of the file. The button lets you go back to the browser when you’re done writing.

The text view should appear between the HStack and button. Add the following line of code between the HStack and button:

If you build and run the project, you should be able to create a new document and type in it.

Connect the Text View to the Document

For the app to do more than let people type text in a text view, you must connect the text view to the document so the text you type updates the document as well. In the document view, you should see the following variable:

This variable contains a reference to the document. Make the following changes to the variable:

The @State property wrapper will allow the text view to bind to the document in order to display the document’s text. Changing the type of the variable to Document is also necessary for the text view to work with the document properly.

Now add the following property to the text view:

The @Binding property wrapper binds the document property in the text view to the document property in the document view. The text view and document view are both pointing to the same document. The text view now has access to the document.

Now that you created the binding you must go back to the document view and change the call to create the text view by supplying the document as an argument.

The $ at the start of $document indicates that you are passing a binding to the text view. You must pass a binding so the document view and text view both point to the same document.

Fill the updateUIView Function

Now that the text view has access to the document, you can write the text view’s updateUIView function. Set the text view’s contents to the document’s contents.

Handling Text Changes

One last thing to do is to update the document when the text view contents change. Add the following function to the Coordinator class:

The first line of code sets the document’s contents to the text view’s contents. The second line marks the document as changed so it will be saved.

Save the Document

At this point you’re finished with the SwiftUI material, but there’s still some work to do to finish the app. The text editor is missing one really big feature: saving text. Open the Document.Swift file. Xcode created a blank contents function for saving the document.

What you have to do is convert the text in the document to a Data object and archive that object. Apple provides the NSKeyedArchiver class and an archivedData function so you can do both steps in one line of code.

The root object is the document’s text. Requiring secure coding ensures your app will be able to unarchive the data when loading the document.

Load the Document

After saving the document, the next task is to load the document when someone chooses a document from the browser. Xcode supplies a blank load function, where you write the code to load the document from disk.

The first argument to the load function is the contents of the file. You must first cast the contents to the Data type. Call the NSKeyedUnarchiver class’s unarchiveTopLevelObjectWithData function to unarchive the text from the file. The last step is to set the document’s text to the contents of the file.

Conclusion

Now you have a simple, working text editor. You can create documents, edit text, save documents, and open them. You can use this project as a foundation for building your own text editing app, such as a Markdown editor. I have the project on GitHub for you to download if you run into issues.

Using Text Views in a SwiftUI App

SwiftUI currently lacks native support for text views. (Note: Xcode 12 adds text view support to SwiftUI). If you want people to enter large amounts of text in a SwiftUI app, you have to wrap a UIKit or AppKit text view. This article shows you how to use a text view in an iOS app that uses SwiftUI. Most of this material should also apply to Mac apps. Replace anything that has a UI prefix with NS.

UIViewRepresentable

To use UITextView in a SwiftUI app, you must create a struct for the text view and have it conform to the UIViewRepresentable protocol. The UIViewRepresentable protocol is how you wrap UIKit views in SwiftUI apps.

Don’t forget to import the UIKit framework.

Create the View

To conform to the UIViewRepresentable protocol, you must add two functions to the struct you created. The first function is makeUIView, which creates and configures the view. It takes an argument of type Context and returns the type of view you want to create, which is UITextView for a text view. The Context type is a type alias for the context where updates to the UIKit view take place. The following code shows an example of creating and configuring a text view:

At a minimum you must create the view and return it. In the code sample I decided to make the text view scrollable and editable. I also added some padding so the text isn’t on the left edge of the screen.

Update the View

The second function you must write is updateUIView, which handles updates to the view. The updateUIView function takes two arguments: a view and a context.

I will be filling the function later in the article.

Try Creating Your Own Text View

At this point you have enough to add a text view to a SwiftUI app. Create an iOS app project in Xcode. Add a file for the TextView struct. Fill the struct with the code I’ve shown so far in the article. Open the ContentView.swift file and replace the text label in the body property with a text view.

Build and run the app. You should be able to type in the text view.

Connecting to Your Data Model

At this point you can type in the text view, but you’ll lose what you type when you quit the app. For a text view to be useful, it needs a connection to your app’s data model.

In the struct for the text view, add a property for the data model. For a simple app, you can create a @State property wrapper that holds the text.

In a real app you’re more likely to have a reference to the data model in another SwiftUI view. Use the @Binding property wrapper to access data from another SwiftUI view.

Replace MyModel with whatever the name of your data model is.

Now that you have a connection to your data model, you can fill in the updateUIView function. Make the text view show the text from the data model.

Coordinators

In order for a UIKit view to communicate with data in SwiftUI, the view needs a coordinator. To conform to the UIViewRepresentable protocol, you must add a new function to the TextView struct, makeCoordinator. The makeCoordinator function creates the coordinator. The return type takes the form StructName.Coordinator.

The next step is to set the text view’s delegate to the context’s coordinator. Add the following line of code to makeUIView before the return statement:

The last step is to add a class for the coordinator. Create a class for the coordinator inside the struct for the text view. Make sure the name of the class matches the name you supply to the makeCoordinator function.

The Coordinator class inherits from NSObject, which is the base class for all UIKit and AppKit classes. A coordinator for a text view should conform to UITextViewDelegate so it can respond to text view notifications, such as the contents of the text view changing.

The coordinator needs a property for the control it’s going to coordinate. The control property contains a reference to the text view.

The Coordinator class needs an initializer to set its view, which is the control property in the code sample.

The last block of code tells the coordinator to respond when the contents of the text view change. The function sets the model’s contents to the text view’s contents. If you want the text view to handle other notifications, add the functions to the coordinator.

Responding to Text Changes in Mac Apps

Responding to text changes has more differences in Mac apps. Let’s look at the code to respond to text changes on Mac.

The name of the function is textDidChange. Instead of taking the text view as an argument, it takes a notification. The object property of the notification is the object that sent the notification. When entering text, the text view is the object that sends the notification that the text changed. The guard statement ensures the object that sent the notification is a text view. The property to get the text in NSTextView is string, not text.

Summary

To use UIKit views in a SwiftUI, you must perform the following tasks:

  • Create a struct for the view that conforms to the UIViewRepresentable protocol.
  • Write the makeUIView function to create and configure the view.
  • Write the updateUIView function so SwiftUI can update the view.
  • Write the makeCoordinator function to create a coordinator for your view to communicate with SwiftUI data.
  • Create a class for the coordinator.

I have a simple plain text editor project on GitHub if you want to see an example of a SwiftUI project that uses a text view.

Learn SwiftUI or UIKit?

With the release of SwiftUI in iOS 13, a common question from people new to iOS development is whether they should learn SwiftUI or UIKit.

Why Learn SwiftUI

The most compelling reason to learn SwiftUI is it’s the future. 2–3 years from now, most iOS developers will use SwiftUI to build their user interfaces. You’re eventually going to need to learn SwiftUI so you might as well learn it now. It makes sense to learn SwiftUI instead of learning UIKit and learning SwiftUI a year or two later.

SwiftUI Limitations

SwiftUI is new technology. At the time I’m writing this, SwiftUI has been out for six months, and three of those months it was in beta. Because SwiftUI is new technology, it has bugs and missing features. Apple is going to be making changes to SwiftUI over the next few years so there’s going to be a lot of work keeping up with the changes. Should you decide to learn SwiftUI instead of UIKit, prepare for a lot of frustration.

Apple’s SwiftUI documentation is limited at best. Many outsiders have been writing books, articles, and tutorials on Swift UI. But at this time, everyone is a beginner at SwiftUI development. There’s much less SwiftUI learning material than UIKit.

SwiftUI has a limited set of user interface elements. For example SwiftUI currently lacks text views and collection views.

SwiftUI apps don’t run on iOS 12 and earlier iOS versions. For people new to iOS development, this isn’t a big limitation, but it is a limitation.

Why Learn UIKit

UIKit is mature and stable. It has all the available iOS user interface elements. There is a lot more UIKit learning material available than SwiftUI.

If you want to use a text view, collection view, or another view that SwiftUI doesn’t have, you need to know some UIKit.

Should You Learn SwiftUI or UIKit?

If you can put up with the SwiftUI limitations I mentioned earlier and deal with limited documentation, learn SwiftUI. Otherwise learn UIKit.

Creating a Simple SwiftUI App

SwiftUI is Apple’s new framework for building user interfaces in Swift. Let’s introduce SwiftUI by creating a simple app. The app displays the number of times you tap a button. I couldn’t think of a simper app idea.

I’m going to focus on making an iOS app in the article, but you can also make a Mac version of this app. Create a macOS App project instead of an iOS project.

Apple added SwiftUI support in Xcode 11 so you must be running Xcode 11 or higher to use SwiftUI.

Create the Project

Create a single-view iOS app (App on Xcode 12) project. Choose SwiftUI from the User Interface menu. Deselect all the checkboxes.

When you create the project, the project navigator should look similar to the following screenshot:

ProjectNavigatorSwiftUIProjectStart

The file you’re going to edit in this article is ContentView.swift. This file contains the main view for the app’s user interface. You will be adding controls to the content view.

The Content View

Open the ContentView.swift file. You’ll see the following struct for the content view:

The body property contains the main view. In the code Apple supplies, the view consists of a label (the Text struct is a label) with the text Hello, World!. If you build and run the project, you will see the label.

Previews and the Canvas

If you look at the end of the ContentView.swift file, you’ll see the following struct:

That struct is for displaying a preview of the view in Xcode’s canvas. The canvas is next to the Swift file in Xcode so you can view your source code and the canvas side by side..

I’m not going to use previews and the canvas in this article. I find the canvas gets in the way, is flaky, and doesn’t help much. But the canvas is there for you if you want it. You can toggle the canvas on and off using a button on the right side of the jump bar.

ToggleCanvas

The button is at the top left in the screenshot.

Change the Label

Let’s start by changing the label’s text to Taps:. Change the code for body to the following:

Build and run the project, and you should see the label’s text is Taps:.

You can modify how the text in the label looks using functions and properties of the Text struct. Start with a period. The following code displays the label in bold text:

The following code changes the font to the system title font:

Add a Variable to Store the Tap Count

To display the number of times someone taps the button, you need a variable to store the number of taps. Add the following code before the body variable:

You must use the @State property wrapper so you can change the value of taps when someone taps the button. If you omit the @State part, you will get a compiler error saying that you’re trying to change an immutable value.

Now modify the label so it also shows the number of taps.

Build and run the project. The label will show zero taps.

Place the Label in a Stack

The next logical step is to add a button. But you can’t just add the button after the label.

The compiler will complain about that code. You have to place the label and button inside a stack. Start by placing the label inside a stack.

I placed the label in a vertical stack. When you add the button, it will appear below the label. Build and run the project. There aren’t any visible changes, but you’re ready to add the button now.

Add the Button

Let’s add the button to the stack in the content view.

The button’s title, Tap Me, is in parentheses. A closure for the button’s action (what happens when someone taps the button) follows. For this app you increment the taps variable. If you have more complicated behavior, write a function and call that function from the closure.

Build and run the project. The number of taps increases each time you tap the button.

Add Space Between the Label and Button

The app works, but there’s not much space between the label and button. Use the padding function to add some padding between the label and button.

If you supply no arguments, the padding function adds a small amount of space. To add more space, you can supply the edge to apply the padding and the amount. The following line of code provides 100 points of padding at the bottom:

When you build and run the project, you should see better spacing between the label and button.

Challenge

Add a Reset button that sets the taps variable back to zero. Don’t forget to add padding between the two buttons. I have the project on GitHub if you get stuck.

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.