Create a SwiftUI application in AppCode
In this tutorial, you'll create a simple SwiftUI application that shows a list of iOS conferences. The application will consist of two views:
A list of conferences representing data from a local JSON file.
Details on each conference.

Along the way, you'll get familiar with AppCode features and learn how to enable an interactive SwiftUI preview.
Watch our video tutorial and follow the step-by-step instructions below:
Step 1. Create a project
Projects created in AppCode are fully compatible with Xcode and use the same project model. After you create a project in AppCode, you can open and edit it in Xcode and vice versa, and everything will be synchronized.
Launch AppCode and click New Project on the Welcome screen:

If you have another project open in AppCode at the moment, select from the main menu.
In the dialog that opens, you see the list of Xcode project templates. Select and click Next:

On the next page, adjust the general project settings:

Product Name: your project name which will also be the name of your application. Type iOSConferences.
Organization Identifier: your or your company's identifier in reverse-DNS format, for example,
com.mycompany.Make sure that Swift is selected as a programming language and SwiftUI as the user interface.
Leave all checkboxes deselected.
In the Finder window that opens, select a directory where your project will be located.
A new Swift project will be created and immediately opened in AppCode.

Step 2. Enable SwiftUI preview
To enable SwiftUI preview in AppCode, you need to install either the HotReloading Swift Package or the InjectionIII application.
Prepare your project
Add the HotReloading package to your project from Xcode:

Alternatively, install and run the InjectionIII application.
Add the
-Xlinker -interposableflag to the Other Linker Flags section of the project build settings ⌃ ⌥ ⇧ S:
Open the iOSConferencesApp.swift file and in the
iOSConferencesAppstructure, add theinit()method with the code that loads the InjectionIII bundles:import SwiftUI @main struct iOSConferencesApp: App { // Add this method init() { #if DEBUG var injectionBundlePath = "/Applications/InjectionIII.app/Contents/Resources" #if targetEnvironment(macCatalyst) injectionBundlePath = "\(injectionBundlePath)/macOSInjection.bundle" #elseif os(iOS) injectionBundlePath = "\(injectionBundlePath)/iOSInjection.bundle" #endif Bundle(path: injectionBundlePath)?.load() #endif } var body: some Scene { WindowGroup { ContentView() } } }Go to the ContentView.swift file. In
ContentView_Previews, add the#if DEBUGblock with theinjected()method inside and convertstructtoclass:class ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } #if DEBUG @objc class func injected() { let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene windowScene?.windows.first?.rootViewController = UIHostingController(rootView: ContentView()) } #endif }
Run the application with preview
Select a device or simulator on the toolbar:

Press ⇧ F10 or click
.
If the HotReloading package was added to your project, you will see the following message:

By default, the interactive preview will work for the files under the home directory. You can specify other directories (separated by commas) in the
INJECTION_DIRECTORIESenvironment variable.If you are using InjectionIII, you'll see the following messages once the application is connected:

Duplicate the
Textcontrol, save the file (⌃ S), and see the changes on the simulator or device screen:
If you don't want to save changes manually to update the preview, go to , select the Save files automatically if application is idle for … sec checkbox, and set its value to 1.
Step 3. Create a list
Let's add a List control and adjust its appearance.
1. Rename the view
Place the caret at
ContentView, press ⇧ F6, typeConferenceListin the highlighted area, and press ⏎.Click
and select the Comments and strings checkbox.
In the Find tool window that opens, click Do Refactor. AppCode will modify the usages of this symbol everywhere including filenames and comments.

The same way, rename
ContentView_PreviewstoConferenceList_Previews.
2. Create a surround livee template for SwiftUI elements
Wrap the
Textcontrol in aList:struct ConferenceList: View { var body: some View { List { Text("Hello, world!") .padding() Text("Hello, world!") .padding() } } }The preview will display this change:

Select the
Listcontrol in the editor, press ⌃ ⇧ A, and find the Save as Live Template… action:
In the dialog that opens, modify the template text:
$ELEMENT$ {$SELECTION$}Make the template applicable in Swift declarations and statements (click the Change link in the bottom-left corner of the dialog).
Add an abbreviation for the template, for example,
sut, rename the custom template group to SwiftUI, and click OK:
Now you can use this template to surround your code with SwiftUI elements. Select the code lines that need to be surrounded, press ⌃ ⌥ T, and choose the new template from the list:

3. Change the list appearance
Add a title to the list. To do this, wrap the list in
NavigationViewand call thenavigationBarTitle(_:)method:struct ConferenceList: View { var body: some View { NavigationView { List { Text("Hello, world!") .padding() Text("Hello, world!") .padding() }.navigationBarTitle("Conferences") } } }Instead of two list items, create one that consists of a title and subtitle. In the title, display the conference name and in the subtitle — location. To do this, wrap the two
Textcontrols in aVStackcontainer, change their values, and apply the corresponding font styles to them:struct ConferenceList: View { var body: some View { NavigationView { List { VStack { Text("Conference").font(.headline) Text("Location").font(.subheadline) } }.navigationBarTitle("Conferences") } } }Align both
Textcontrols left using thealignmentparameter for theVStackcontainer:VStack(alignment: .leading) { // … }
In the end, the list will look as follows:

Step 4. Load data from JSON
Next, we will add a JSON file with conferences data to our project and display this data in the ConferenceList view.
1. Add a JSON file to the project
Download the conferencesData.json file from our repository.
Select the
iOSConferencesgroup in the Project tool window, press ⌘ N, and choose Group.In the dialog that opens, type Resources, make sure the Create folder, checkbox is selected, and click OK:

Right-click the
Resourcesgroup, select and locate the downloaded JSON in Finder.
2. Parse the JSON file
Let's add a function for parsing the JSON data into an array of Decodable objects and create a data model for these objects.
In the iOSConferences group, create a group called Model.
Create a new Swift file there (New | Swift File) and call it Data:

In the newly created file, add the
loadFile()function that we will use to decode the JSON file:func loadFile<T: Decodable>(_ filename: String) -> T { let data: Data guard let file = Bundle.main.url(forResource: filename, withExtension: nil) else { fatalError("Cannot find \(filename)") } do { data = try Data(contentsOf: file) } catch { fatalError("Cannot load \(filename):\n\(error)") } do { let decoder = JSONDecoder() let format = DateFormatter() format.dateFormat = "yyyy-mm-dd" decoder.dateDecodingStrategy = .formatted(format) return try decoder.decode(T.self, from: data) } catch { fatalError("Cannot parse \(filename): \(T.self):\n\(error)") } }In the Model group, create the
ConferenceSwift class () :
The
Conferenceclass should conform to theCodableandIdentifiableprotocols and include a set fields that correspond to the parsed JSON data:class Conference: Codable,Identifiable { var name: String var location: String var start: Date var end: Date? var link: String }In Data.swift, introduce the
conferencesDatavariable that will store an array ofConferenceobjects parsed from the JSON file:let conferencesData: [Conference] = loadFile("conferencesData.json")
3. Display conferences in the list
Now when we have the array of conferences saved in the conferencesData variable, we can pass it to ConferenceList.
Go to the ConferenceList.swift file and pass
conferencesDatato theListinitializer:List(conferencesData) {conference in … }.navigationBarTitle("Conferences")Now the list displays as many items as the
conferencesDataarray contains:
Finally, replace the
ConferenceandLocationstrings with the real data:List(conferencesData) {conference in VStack(alignment: .leading) { Text(conference.name).font(.headline) Text(conference.location).font(.subheadline) } }.navigationBarTitle("Conferences")
The updated list will look as follows:

Step 5. Add the details view
The second view of our application will display the detailed information on each conference.
1. Create a new SwiftUI file
In the Project tool window, select the
iOSConferencesgroup, press ⌘ N, and select File from Xcode Template….In the dialog that opens, select and click Next:

On the next page, type the filename — ConferenceDetails, make sure that the iOSConferences group and location are selected, and click Finish.
Enable the interactive preview for the new view in
ConferenceDetails_Previewsthe same way you did it forConferenceList_Previews:class ConferenceDetails_Previews: PreviewProvider { static var previews: some View { ConferenceDetails() } #if DEBUG @objc class func injected() { let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene windowScene?.windows.first?.rootViewController = UIHostingController(rootView: ConferenceDetails()) } #endif }
2. Set up navigation between the views
To set up connection between the views, we will use the NavigationLink functionality.
In the
ConferenceList.swiftfile, wrap theVStackcontainer in aNavigationLink.NavigationLink { VStack(alignment: .leading) { Text(conference.name).font(.headline) Text(conference.location).font(.subheadline) } }Pass the
ConferenceDetailsview to thedestinationparameter of theNavigationLink:NavigationLink(destination: ConferenceDetails()) { VStack(alignment: .leading) { Text(conference.name).font(.headline) Text(conference.location).font(.subheadline) } }The list items are now clickable, and the details view opens on tapping each of them:

3. Pass conference data to the details view
The ConferenceDetails view should display the detailed information on the conference selected in the list.
Go to the
ConferenceDetailsview and replace the defaultHello, World!text with the conference location:struct ConferenceDetails: View { var body: some View { Text(conference.location) } }The
conferencefield is not added yet, that's why its usage is highlighted in red. Apply the Create property 'conference' intention action (⌥ ⏎) to create the field:
As a result, you should have the following code:
struct ConferenceDetails: View { var conference: Conference var body: some View { Text(conference.location) } }After adding the new field, we need to pass it as a parameter to all the
ConferenceDetails()initializer calls. Press F2 to navigate to the error-causing code, place the caret atConferenceDetails(), and press ⌥ F7 to find all usages of this initializer.In the Find tool window, you will see all the calls we need to fix. Place the caret at the highlighted code, press ⌥ ⏎, and select Apply Fix-it:

In the ConferenceDetails.swift file, pass
Conference()as theconferenceparameter in both usages:class ConferenceDetails_Previews: PreviewProvider { static var previews: some View { ConferenceDetails(conference: Conference()) } #if DEBUG @objc class func injected() { let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene windowScene?.windows.first?.rootViewController = UIHostingController(rootView: ConferenceDetails(conference: Conference())) } #endif }In ConferenceList.swift, change the initializer call as follows:
NavigationLink(destination: ConferenceDetails(conference: conference)) { … }Conference()is still highlighted because theConferenceclass doesn't have any initializers. To add one, place the caret atConference(), press ⌥ ⏎, and select Create initializer:
An empty
init()method will be added to theConferenceclass. Set initial values for all the properties there, for example:init() { name = "Conference Name" location = "Location" start = Date() end = Date() link = "https://www.google.com" }
Now take a look at the preview. The ConferenceDetails view displays the location of the conference selected from the ConferenceList view:

4. Display conference dates and links
Duplicate ⌃ D the
Text(conference.location)line two times:struct ConferenceDetails: View { var conference: Conference var body: some View { Text(conference.location) Text(conference.location) Text(conference.location) } }The conference start and end dates should be displayed in the following format:
MMMM dd, yyyy - MMMM dd, yyyy. To do this, we need to convertDatetoString. Let's use a newtextDates()method for this purpose and call it for the secondTextcontrol:struct ConferenceDetails: View { var conference: Conference var body: some View { Text(conference.location) Text(conference.textDates()) Text(conference.location) } }Place the caret at the highlighted code, press ⌥ ⏎, and select Create method 'textDates':

An empty
textDates()method will be created in theConferenceclass. Add the following code there:func textDates() -> String { var result = start.dateToString() if let end = self.end { result = "\(result) - \(end.dateToString())" } return result }This method uses the
dateToString()utility function that we will add to theDateclass. Go toData.swiftand add the following code there:extension Date { func dateToString() -> String { let format = DateFormatter() format.dateFormat = "MMM dd, yyyy" return format.string(from: self) } }The conference dates now appear in the details view:

Implement the
LinkButtoncontrol which will display a clickable link to conference websites. InConferenceDetails.swift, add the following code:struct LinkButton: View { var link = "" var body: some View { Button(action: { UIApplication.shared.open(URL(string: self.link)!) }) { Text("Go to official website") } } }Now replace the third
Textcontrol withLinkButton:struct ConferenceDetails: View { var conference: Conference var body: some View { Text(conference.location) Text(conference.textDates()) LinkButton(link: conference.link) } }The new control will immediately appear in the preview:

5. Adjust the details view appearance
The only thing left now is to enchance the details view layout.
In the
ConferenceDetailsview, wrap theTextcontrols and theLinkButtonin aVStackcontainer and move it to the top-left corner of the screen adjusting its frame's width, height, and alignment:struct ConferenceDetails: View { var conference: Conference var body: some View { VStack { Text(conference.location) Text(conference.textDates()) LinkButton(link: conference.link) }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading) } }Align the
VStackcontent left:VStack(alignment: .leading) { // … }Add the default padding for the
VStackcontainer:VStack(alignment: .leading) { // … }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading) .padding()Add the bottom padding for the elements within the
VStackcontainer:VStack(alignment: .leading) { Text(conference.location).padding(.bottom) Text(conference.textDates()).padding(.bottom) LinkButton(link: conference.link).padding(.bottom) }Show the conference name in the view title using the
navigationBarTitle(_:)method:VStack(alignment: .leading) { // … }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading) .padding() .navigationBarTitle(conference.name)Finally, the
ConferenceDetailsview will look as follows:
What's next
You can elaborate this application by making it load the data from the remote YAML file containing the up-to-date list of iOS/macOS conferences. For parsing the data, you can use the Yams library added to the project by means of the CocoaPods dependency manager. See more in the Use CocoaPods in your project tutorial.