ios swift xcode 效率 File Template 文件模板,Project Template 项目模板

原文地址:https://www.raywenderlich.com/26582967-xcode-project-and-file-templates

If you’re tired of filling out boilerplate code whenever you begin a new Xcode project, you can save yourself a ton of time by creating customized project templates.

Using Xcode’s project and file templates , you have the power to customize how new projects and files start out their life from the moment you use File ▸ New. These templates allow you to pre-fill the contents of new files and project so that you can get to work on the core of your next excellent app idea more quickly.

In this tutorial, you’ll learn:

  • What Xcode templates are and where to find the default templates that ship with Xcode.
  • The anatomy of Xcode’s templates.
  • How to create project templates.
  • How to create file templates.
  • Getting input from users when they use a template.

Get ready because you’re about to replace some unnecessary boilerplate with custom Xcode templates!

Getting Started

First, click the Download Materials button at the top or bottom of this tutorial to download the project materials.

In this tutorial, you’ll build an app called Stellar Space which uses NASA’s Astronomy Picture of the Day API to show today’s latest space-related and wallpaper-worthy photo. Along the way you’ll how to create your own templates.

Picture of the day in the Stellar Space app

Note: The starter materials don’t contain a starter Xcode project. That’s because you’ll be creating the project by yourself, using custom Xcode project templates!

Imagine for a moment that you are a big fan of the Model-View-ViewModel (MVVM) design pattern. You want to use it in all your apps, and this app is no different. Usually, a new SwiftUI app comes with a ContentView.swift for you to use for the first screen of your app. But instead of using the default template, you’ll create your own template that pairs ContentView with a view model to separate the UI and business logic. Using that template will make your life easier when creating your projects.

Since Xcode’s templating system is robust but poorly documented, you’ll need to explore the default templates Xcode offers so you can know what you can customize.

Understanding Default Templates

Every time you’ve created a new Xcode project in the past, you did so using Xcode’s default templates. These default templates make things easier than starting with a blank project.

Templates decide what your new project will contain. The default templates include many different options including, but not limited to:

  • A blank view with a “Hello, World!” text.
  • Setup code for your Core Data implementation
  • A fully functioning ARKit scene

Xcode’s rich and complex templating system also allows user input, conditional logic and many combinations of files. Each template also offers inheritance, meaning the templates you create can adopt logic from one another or the default templates.

Inheritance also means that all the fantastic behavior of the default templates is up for grabs. Consequently, looking at the default templates is a great way to start creating templates of your own.

Exploring Base Templates

Xcode stores the default templates within the Xcode app bundle itself. To take a look at all the base templates, open a Finder window. You can do this by opening Finder and pressing Shift-Command-G or going to Go ▸ Go to Folder…. Then, copy and paste the location of the default project templates into the resulting window:

/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/Project Templates

Finder's folder navigation pop-up containing project templates' folder path

Next, click Go.

Folder content of the Project Templates

The Base folder contains templates that you won’t see directly in Xcode’s New Project dialog. These base templates are abstract, and they serve as good starting points that other templates can inherit from.

Folder structure of the Project Template's Base folder

The Base folder contains most of Xcode’s default templates. iOS templates are in a different folder. You’ll look at those next.

Exploring iOS Templates

In Finder, go to Go ▸ Go to Folder… again. Then, enter the location of the default iOS templates as follows:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Templates/iOS

Click Go.

Folder content of the iOS Project Templates

You’ll see the iOS folder. Here, you’ll find templates for the iOS category in Xcode, as seen in this screenshot:

Xcode pop-up with the iOS categories available for choosing a template for creating a new project

Open the Application subfolder in Finder, and then open App.xctemplate.

Folder content of App.xctemplate

Take a look. When you create a new iOS app, Xcode uses this template. Next, you’ll copy this template to a different location so you can customize it and make it your own.

Creating Your First Project Template

Now it’s time to create your custom project template. There are three basic steps:

  1. Copy an existing template. In this case, App.xctemplate.
  2. Create a folder to store all your custom templates.
  3. Modify the copied template to match your needs.

First, while in the iOS default templates folder, right-click App.xctemplate and click Copy.

Next, open a new Finder window. Press Command-Shift-G or go to Go ▸ Go to Folder… and type in the path to the Xcode folder in your user library:

~/Library/Developer/Xcode

Then, click Go.

Contents of the Xcode folder

The Xcode folder stores device logs, application archives and other user data. Most importantly, for now, it also stores your custom templates. It is in your home directory and therefore is specific to your user account on the machine.

To create new custom template subfolder, right-click in this folder and then click New Folder. Name the subfolder Templates. Then, open the new Templates subfolder.

Create a new subfolder named Templates and open it in finder

This folder will store your custom templates. Now, right-click in the folder and click Paste Item to paste the copied App.xctemplate.

Next, rename the item you just pasted from App.xctemplate to View Model App.xctemplate.

Your new template looks like this:

Content of custom template, View Model App.xctemplate

To make your template work, you’ll need to give it an unique identifier. Inside View Model App.xctemplate, open TemplateInfo.plist with Xcode.

Contents of TemplateInfo.plist

Change the value for Identifier to com.raywenderlich.mvvm.

Voilà! :] You just created a new custom template!

However, you’ll need to add code to make it more meaningful. Xcode knows to read templates in the folder you just created. However if Xcode is already open, you need to quit and restart to enable your changes. Then, go to File ▸ New ▸ Project… to open the New Project dialog.

Scroll to the bottom of the iOS category. Here, you’ll find a new Templates section that holds your custom templates.

Xcode pop-up to choose custom templates

Select View Model App and click Next.

Template options for first custom template

Your template comes with the same rich list of options as the default app template. How does a simple template exhibit all that behavior?

Contents of a Template

You’re now going to look at the template you just created to learn what makes up a template.

Go back to Finder and open View Model App.xctemplate.

Inside the template, you’ll find:

  • TemplateInfo.plist: The file which is the driving force behind the template. This file contains the logic that determines what you’ll see in the New Project dialog and how to interpret any user input.
  • Any other files that will be used to form the template project. Currently, you’ll only see Main.storyboard as that’s the only file necessary to kick off the project.

Usually, a SwiftUI app starts with a ContentView.swift file, but it’s missing from this template folder. That’s because this template inherits ContentView.swift indirectly from another template called iOS SwiftUI App.xctemplate, located in the same folder as the original App.xctemplate you copied.

App.xctemplate inherits from Core Data Cocoa Touch App.xctemplate, which in turn inherits from iOS SwiftUI App.xctemplate. It’s templates all the way down! :]

Now that you’ve reviewed the templates, you’ll create a template ViewModel.swift file and connect it with your custom template’s ContentView.swift. This will be the first customization of the template you’ll do to start seeing the power of custom templates!

Customizing the Project Template

The first step to customizing your project template is creating a view model class.

Open Terminal.app and enter the following:

touch ~/Library/Developer/Xcode/Templates/View\ Model\ App.xctemplate/ViewModel.swift

Note: Make sure you’ve created View Model App.xctemplate with the exact name and location as instructed, or the previous command won’t work.

Terminal to run the touch command to create ViewModel.swift

This command creates an empty ViewModel.swift file within your template.

ViewModel.swift added in the custom project custom template

Next go back to Finder and open ViewModel.swift in Xcode. At the moment, it’s blank, so add the following code to its contents:


import Foundation
import Combine

class ViewModel: NSObject, ObservableObject {
  @Published var title = "Hello, world! :]"
}

This creates a template ViewModel class that will drive your app’s view behavior.

With the code above, you’ve done a few things:

At the top is the ___FILEHEADER___ text macro. This macro is defined by Xcode and populates the file with copyright information, including your name, the current date, and the file name. ___FILEHEADER___ looks like this:

//  ___FILENAME___
//  ___PACKAGENAME___
//
//  Created by ___FULLUSERNAME___ on ___DATE___.
//  ___COPYRIGHT___
//

After ___FILEHEADER___, the code added the necessary imports and defined the ViewModel class containing a title string for now.

Save and close ViewModel.swift.

Your template will now create ContentView.swift from the inheritance described earlier and also ViewModel.swift from the file you just added. But you haven’t done anything to tell your template to add these files to a new Xcode project. To do this you’ll dive into TemplateInfo.plist. First, take a look at what the TemplateInfo.plist contains.

Working With Project Template Info

TemplateInfo.plist is the brains of your template. It instructs the template how to connect with ViewModel.swift. Next, you’ll explore TemplateInfo.plist‘s contents and create those instructions.

Open TemplateInfo.plist with Xcode.

Custom Project TemplateInfo.plist in Xcode

Below are some essential keys you’ll find inside the property list:

  • Kind: The type of template. In this case it is Xcode.Xcode3.ProjectTemplateUnitKind, which means it’s a project template.
  • Identifier: A unique identifier for your template.
  • Ancestors: A list of identifiers of other templates that this template inherits from. You’ll see two items in this array: com.apple.dt.unit.coreDataCocoaTouchApplication and com.apple.dt.unit.sceneLifecycleApplication.
  • Concrete: Indicates if the template is available directly while creating a new project in Xcode. Since you want to use this template to create a custom project, set it to true. If set to false, you can’t use the template directly as it will be an abstract base template from which your other templates can inherit information.
  • Description: A short description of the template.
  • SortOrder: Usually, Xcode arranges templates alphabetically, but you can set the sort order here to override the alphabetical sorting.
  • NameOfInitialFileForEditor: Indicates the file that Xcode will display once the new project is ready.
  • Options: A list of different dialog options in the New Project dialog. Options is the most complex as well as the most important of all the keys. Using Options, you can ask the user for input in the form of text fields, checkboxes and drop-down lists. Additionally, the Options section determines how to interpret user input.

Next, you’ll learn more about these options so you’ll know what “options” you have when you’re building your custom template.

Exploring Options

Click the arrow to the left of Options to open it. Then, do the same to open Item 1.

Options under Custom Project TemplateInfo.plist in Xcode

This option allows users to choose the interface type for their projects. They can choose either SwiftUI or Storyboard.

Choosing the interface type while creating a new iOS project

You want to add ViewModel.swift to the project if the user chooses SwiftUI. You’ll do that shortly.

Here’s what’s inside the Item 1 dictionary:

  • Identifier: A unique identifier to reference the option.
  • Name: The name of the option that the user will see in the New Project dialog.
  • Description: A short description of the option’s purpose.
  • Values: A list of possible values for popup type options.
  • Default: A default value in case the user doesn’t choose one.
  • Type: The type of the option, either popup, checkbox or text.

Bravo! You just finished learning the anatomy of the brain of a template. It’s time to now feed in your custom code. :]

Adding the View Model

So far, you’ve used Xcode’s Property List Editor to navigate TemplateInfo.plist. Xcode is a great way to view and tweak property lists, but it can be tough to make larger changes. Instead, you’ll edit the raw XML.

Open TemplateInfo.plist in TextEdit.app or your favorite text editor. Then, near the bottom of the file, find Values. It’ll look like this:

Interface Values in TemplateInfo.plist

Remove the Values key as well as the array under it. Replace it with this:

Units

  SwiftUI
  
    
      Nodes
      
        ViewModel.swift
      
      Definitions
      
        ViewModel.swift
        
          Path
          ViewModel.swift
        
      
    
  
  Storyboard
  

Save the file and reopen it in Xcode. It will look like this:

Interface Units type in TemplateInfo.plist opened in Xcode

Here’s what’s in the items above:

  1. Units is a list of values for the option, along with the behavior for each value.
  2. Each item in the dictionary is a Value that the user will see in the New Project dialog. Currently, the values are SwiftUI and Storyboard, which are the same as the old Values.
  3. Under the SwiftUI value, there’s a dictionary for your added behavior.
  4. Nodes is a list of files that will be included if the user chooses the SwiftUI value as the option for userInterface.
  5. Definitions contains the actual path for any files in Nodes.
  6. A Storyboard value that’s the same as the one in the old Values, without any behavior.

You’re finally ready to use your template to actually create your project!

Using the Template

Now, you’ll use the template you just set up. First, close Xcode, then reopen it for your changes to take effect.

Go to File ▸ New ▸ Project… to open the New Project dialog. Scroll to the bottom of the iOS category and select your View Model App template. Click Next.

Select the View Model App template while creating a new project in Xcode

On the next screen, set the following values for the options:

  • Product Name: Stellar Space.
  • Organization Identifier: com.raywenderlich.
  • Interface: SwiftUI.
  • Language: Swift.

Click Next, and then Create.

Xcode pop-up to choose options for creating new project

Build and run. You’ll be presented with the classic “Hello, world!” starter screen:

image

You’ll see the ViewModel.swift file in your project structure. However, ContentView isn’t tied to ViewModel yet. In ContentView.swift, add the following inside ContentView, above body:

@ObservedObject var viewModel = ViewModel()

Next, find Text inside body. Then, replace it with this:

Text(viewModel.title)

Build and run.

Starter Screen with Label populated using ViewModel data

You’re now pulling the text from the view model.

You’ve created a project with your custom template and used the new ViewModel. Next, you’ll flesh out the rest of Stellar Space.

Populating the Project

You’ll find most of the files for Stellar Space inside the project materials that you downloaded earlier.

Open the project materials in Finder and select the API and UI folders.

Copying API and UI folder from the start project to the current project

Then, drag these into Xcode’s Project navigator.

The copied folders are linked in the current workspace folder in Xcode

Select the Copy items if needed checkbox. Click Finish.

Select Copy items if needed to include new files in the current project

You’ve added a bunch of Swift files to Stellar Space. Later, you’ll use the files in the API folder to communicate to NASA’s API, and you’ll use the files in the UI folder to beautify your ContentView.

Next, select Assets in Xcode’s Project navigator. Delete the empty AppIcon asset.

Delete the default AppIcon givin in the Assets.xcassets folder

Finally, drag AppIcon.appiconset from the project materials into Assets, right next to AccentColor.

Drag AppIcon.appiconset from the project materials into Assets

You’ve just created Stellar Space’s app icon.

Build and run.

A screen showing errors in the project due to API errors

Oh, no! Looks like there’s an APIError object missing from Stellar Space. APIError is an enum that Stellar Space uses to identify a special group of errors. Don’t worry, because next, you’ll learn about Xcode file templates and create the APIError enumeration in the process.

Creating File Templates

So far, you’ve worked with project templates that Xcode uses to create new projects. But Xcode also uses template files when you add a file to an existing project, so now you’ll work on customizing file templates.

Using file templates reduces the amount of boilerplate you need to write. Therefore, you are best to employee custom file templates when you find yourself often creating new files and writing almost identical boilerplate code to start the file off.

Everything you see in the New File dialog is a template, just like in the New Project dialog.

Xcode pop-up to choose a template for creating a new file

APIError is an enum, so you’ll create an Xcode template that makes a single Swift file with an enum inside. That can be useful as you might often create enumerations and having a template to make life easier doing so will reduce your time spent writing boilerplate code.

To create a Swift Enum template for APIError, you’ll copy and modify the default Swift File template.

Copying a Default File Template

Xcode stores its file templates alongside project templates. In Finder, go to Go ▸ Go to Folder… and type in the path to the default file templates:

/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/File Templates

Click Go.

Xcode library content with File Templates

Open the MultiPlatform subfolder and then the Source folder within. Here, you’ll find the Swift File.xctemplate.

Swift file template under Source folder

Swift File.xctemplate is the template that Xcode uses to create a plain Swift file.

It’s a simple template and a great starting point for your enum template as it’s very close to what you need. Copy Swift File.xctemplate to the location where you stored your custom templates:

~/Library/Developer/Xcode/Templates/

Copy and Paste the Swift File.xctemplate in the Templates folder

Next, within the custom templates folder, rename Swift File.xctemplate to Swift Enum.xctemplate. When you’re done, the custom templates folder will look like this:

Rename Swift File.xctemplate to Swift Enum.xctemplate

Great! But it’s still the boilerplate Swift File template. So, now, you’ll customize it.

Customizing the File Template Info

You’ll use your new Swift Enum.xctemplate template to create APIError.swift, which contains an enum with an Error raw value. So, it’d be great if your template gave users the option to set a raw value for the enum when creating a file from the template. You’ll do that by adding an option to TemplateInfo.plist.

In Swift Enum.xctemplate, open TemplateInfo.plist with Xcode. Change the values for the following keys:

  • Description: A Swift enum with a raw value.
  • Summary: A Swift enum with a raw value.
  • DefaultCompletionName: Enum.

Description and Summary are used by Xcode in the same way as project templates. However, DefaultCompletionName is new. The value of this key will be the name of any file you create if you don’t rename it. In other words, without changing the file name, the template would name a new file Enum.swift.

At this stage, TemplateInfo.plist looks like this:

TemplateInfo.plist for new Swift file

Now you need to include an option to ask the user to enter a raw value for the enum, such as Error. This will be user input that’s used while generating the new file from the template.

To do so, open TemplateInfo.plist in TextEdit.app or any other text editor. Near the top of the file, after the very first , add the following:

Options

 
   Type
   text
   Description
   Raw value for enumeration
   Name
   Raw Value:
   Required
   
   Identifier
   rawValue
   

Your TemplateInfo.plist will look like this when you’re done:

TemplateInfo.plist after adding custom options to choose while creating a new swift file

You’ve added a new Options array with one dictionary inside it. This will tell Xcode to provide an option when using the template. In this case, the single option added represents a Raw Value option to choose a raw value for the enumeration. Here’s what each item in the dictionary means:

  • Type: The type of user input: text, checkbox or popup.
  • Description: A short description of the option.
  • Name: The name of the option that the user will see in the New File dialog.
  • Required: A boolean value to decide whether or not the user needs to enter a value for the option before continuing.
  • Identifier: A unique identifier to reference the value of the option.

You’re done adding file template info. Now, you need to tell the template how to create the Swift file in the way you need.

Creating Template Files

Inside Swift Enum.xctemplate, open FILEBASENAME.swift. This is the file that your file template creates in your project.

___FILEBASENAME___ is a text macro that all file templates have. It’s the name that you choose for the file in the New File dialog, just without the file extension. For example, if you choose APIError.swift as the file name when using the template, then Xcode sets ___FILEBASENAME___ to APIError.

Inside FILEBASENAME.swift, replace the contents with this:

//___FILEHEADER___

import Foundation

enum ___FILEBASENAMEASIDENTIFIER___: ___VARIABLE_rawValue___ {
    case one
    case two
}

You’ve created a simple enum with two default cases. In this file, you use three template macros. Here’s what each of these do.

At the top of the file is ___FILEHEADER___, which sets the usual copyright, file and author details.

Next, instead of a name for the enum, you have ___FILEBASENAMEASIDENTIFIER___. This is the same as the ___FILEBASENAME___ variable for the file name, except that you can’t use ___FILEBASENAME___ inside the template file.

Finally, ___VARIABLE_rawValue___ is a reference to the rawValue option you created earlier. The format looks like ___VARIABLE____.

That’s all you need to set up your template. Quit and reopen Xcode. Next, you’ll use your template to create APIError.swift.

Using the Template

In Xcode, with Stellar Space open, go to File ▸ New ▸ File…. Then, choose your Swift Enum template.

For Raw Value, enter Error. Then, click Next.

Xcode pop-up to enter Raw Value in the Swift Enum template

Name the file APIError.swift and click Create.

Open APIError.swiftcases within APIError and replace them with this:

case network(description: String)
case parsing(description: String)

Finally, build and run.

Starter screen with updated Label text driven from ViewModel

The app compiles! But, you still have some finishing touches to add to ContentView and ViewModel to display more than just a fancy message on the screen. :]

Finishing the Project

On the final stretch now to finish off the project to display those lovely NASA images.

In Xcode, open ViewModel.swift. First, add the following import at the top of the file:

import UIKit

@Published var image: UIImage?
@Published var errorMessage: String?
@Published var isLoading = true
@Published var date = Date()

var canMoveForward: Bool {
  !calendar.isDateInToday(date)
}

var dateString: String {
  let dateFormatter = DateFormatter()
  dateFormatter.dateStyle = .medium
  dateFormatter.timeStyle = .none
  return dateFormatter.string(from: date)
}

private let spaceImageFetcher = SpaceImageFetcher()
private let calendar = Calendar.current
private var disposables = Set()

func changeDate(days: Int) {
  if let newDate = calendar.date(byAdding: .day, value: days, to: date) {
    date = newDate
    loadImage()
  }
}

func loadImage() {
  isLoading = true
  image = nil
  errorMessage = nil
  spaceImageFetcher.dailyPicture(date: date)
    .receive(on: DispatchQueue.main)
    .flatMap { dailyPic -> AnyPublisher in
      self.title = dailyPic.title
      return self.spaceImageFetcher.loadImage(url: dailyPic.url)
    }
    .receive(on: DispatchQueue.main)
    .sink(receiveCompletion: { [weak self] value in
      switch value {
      case .failure(let reason):
        print("Failure: \(reason.localizedDescription)")
        self?.errorMessage = "Something went wrong."
      case .finished:
        break
      }
      self?.isLoading = false
    }, receiveValue: { image in
      self.image = image
    })
    .store(in: &disposables)
}

I won’t explain the code here because it’s not relevant to the tutorial. All you need to know is that this code adds the logic for accessing the NASA API and displaying images.

Then, open ContentView.swift. Replace the declaration of body with this:

var body: some View {
  ZStack {
    ColorPalette.primary.ignoresSafeArea()
    VStack {
      Text(viewModel.dateString)
        .foregroundColor(ColorPalette.accent)
      Spacer()
      if !viewModel.isLoading {
        if let image = viewModel.image {
          Image(uiImage: image)
            .resizable()
            .scaledToFit()
          Text(viewModel.title)
            .foregroundColor(ColorPalette.accent)
        } else if let error = viewModel.errorMessage {
          Text(error)
            .foregroundColor(ColorPalette.secondary)
        }
        Spacer()
        ZStack {
          HStack {
            Button("Back", action: changeDateBack)
              .padding(.leading, 20)
            Spacer()

            if viewModel.canMoveForward {
              Button("Forward", action: changeDateForward)
                .disabled(!viewModel.canMoveForward)
                .padding(.trailing, 20)
            }
          }
        }
      } else {
        ProgressView()
          .progressViewStyle(ProgressViewWithBackgroundStyle())
          .frame(width: 100, height: 100)
        Spacer()
      }
    }
  }
  .onAppear(perform: fetchImage)
  .buttonStyle(SpaceButtonStyle())
}

func changeDateBack() {
  viewModel.changeDate(days: -1)
}

func changeDateForward() {
  viewModel.changeDate(days: 1)
}

func fetchImage() {
  viewModel.loadImage()
}

With this, ContentView has the UI to display everything happening in ViewModel. Build and run.

[图片上传中...(image-564458-1642558611777-0)]

At last, you’ve completed Stellar Space, and you have two new Xcode templates to show for it: a project template and a file template!

Where to Go From Here?

In this tutorial, you created both a project template and a file template, using Xcode’s default templates as a source of inspiration.

You added your files to your templates, controlled them with the Template Options file and customized them with variables.

Templates are a great example of the power of an IDE like Xcode. If you’d like to learn more about how Xcode can make your life easier, iOS App Distribution & Best Practices dives under the hood of the Xcode project structure.

Your project template separates business logic from UI code by including a view model. If you’d like to learn more about project architecture, have a look at Advanced iOS App Architecture. You might get some ideas for new templates, too!

Please join the discussion below if you have questions or comments or want to share some of your creative templates.

你可能感兴趣的:(ios swift xcode 效率 File Template 文件模板,Project Template 项目模板)