Advanced Tutorials

UML to Swift Code Generation

Learn to generate Swift code from UML class diagrams using MTL templates.

In this advanced tutorial, you’ll build a complete code generator that transforms UML models into Swift source files. You’ll learn:

  • Mapping UML classes to Swift structs and classes

  • Generating properties with proper types

  • Creating initialisers and method stubs

  • Handling protocols and enumerations

  • Organising output into multiple files

50 mins Estimated Time

Section 1

Understanding the UML Metamodel

The UML metamodel defines the structure of class diagrams that we’ll transform into Swift code. This simplified UML subset includes Swift-specific features.

Key concepts:

  • Package: Container for classifiers

  • Class: Types with properties and operations

  • Property: Typed attributes with optionality

  • Operation: Methods with parameters and return types

  • Protocol: Interface definitions

  • Enumeration: Fixed value sets

Step 1

Examine the UML metamodel with Swift extensions.

The metamodel includes Swift-specific attributes like isStruct, isFinal, isAsync, throws, isOptional, and isCollection. The VisibilityKind enumeration includes Swift access levels.

uml-class.ecore
1<?xml version="1.0" encoding="UTF-8"?>
2<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="UML" nsURI="http://www.example.org/uml" nsPrefix="uml">
4 <!-- NamedElement: Base class for all named UML elements -->
5 <eClassifiers xsi:type="ecore:EClass" name="NamedElement" abstract="true">
6 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1"
7 eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
8 </eClassifiers>
9 <!-- TypedElement: Elements with a type reference -->
10 <eClassifiers xsi:type="ecore:EClass" name="TypedElement" abstract="true" eSuperTypes="#//NamedElement">
11 <eStructuralFeatures xsi:type="ecore:EReference" name="type" lowerBound="1" eType="#//Type"/>
12 <eStructuralFeatures xsi:type="ecore:EAttribute" name="isOptional" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
13 defaultValueLiteral="false"/>
14 </eClassifiers>
15 <!-- VisibilityKind: Enumeration for visibility modifiers -->
16 <eClassifiers xsi:type="ecore:EEnum" name="VisibilityKind">
17 <eLiterals name="public"/>
18 <eLiterals name="private" value="1"/>
19 <eLiterals name="internal" value="2"/>
20 <eLiterals name="fileprivate" value="3"/>
21 </eClassifiers>
22 <!-- Type: Abstract base for all types -->
23 <eClassifiers xsi:type="ecore:EClass" name="Type" abstract="true" eSuperTypes="#//NamedElement"/>
24 <!-- PrimitiveType: Built-in types (String, Int, Bool, Double, etc.) -->
25 <eClassifiers xsi:type="ecore:EClass" name="PrimitiveType" eSuperTypes="#//Type"/>
26 <!-- Package: Container for classifiers -->
27 <eClassifiers xsi:type="ecore:EClass" name="Package" eSuperTypes="#//NamedElement">
28 <eStructuralFeatures xsi:type="ecore:EReference" name="classifiers" upperBound="-1"
29 eType="#//Classifier" containment="true"/>
30 </eClassifiers>
31 <!-- Classifier: Abstract base for Class, Enum, Protocol -->
32 <eClassifiers xsi:type="ecore:EClass" name="Classifier" abstract="true" eSuperTypes="#//Type">
33 <eStructuralFeatures xsi:type="ecore:EAttribute" name="visibility" eType="#//VisibilityKind"
34 defaultValueLiteral="public"/>
35 <eStructuralFeatures xsi:type="ecore:EAttribute" name="documentation" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
36 </eClassifiers>
37 <!-- Class: UML class with properties and operations -->
38 <eClassifiers xsi:type="ecore:EClass" name="Class" eSuperTypes="#//Classifier">
39 <eStructuralFeatures xsi:type="ecore:EAttribute" name="isStruct" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
40 defaultValueLiteral="false"/>
41 <eStructuralFeatures xsi:type="ecore:EAttribute" name="isFinal" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
42 defaultValueLiteral="false"/>
43 <eStructuralFeatures xsi:type="ecore:EReference" name="superClass" eType="#//Class"/>
44 <eStructuralFeatures xsi:type="ecore:EReference" name="protocols" upperBound="-1" eType="#//Protocol"/>
45 <eStructuralFeatures xsi:type="ecore:EReference" name="properties" upperBound="-1"
46 eType="#//Property" containment="true"/>
47 <eStructuralFeatures xsi:type="ecore:EReference" name="operations" upperBound="-1"
48 eType="#//Operation" containment="true"/>
49 </eClassifiers>
50 <!-- Protocol: Swift protocol definition -->
51 <eClassifiers xsi:type="ecore:EClass" name="Protocol" eSuperTypes="#//Classifier">
52 <eStructuralFeatures xsi:type="ecore:EReference" name="extends" upperBound="-1" eType="#//Protocol"/>
53 <eStructuralFeatures xsi:type="ecore:EReference" name="properties" upperBound="-1"
54 eType="#//Property" containment="true"/>
55 <eStructuralFeatures xsi:type="ecore:EReference" name="operations" upperBound="-1"
56 eType="#//Operation" containment="true"/>
57 </eClassifiers>
58 <!-- Enumeration: Swift enum definition -->
59 <eClassifiers xsi:type="ecore:EClass" name="Enumeration" eSuperTypes="#//Classifier">
60 <eStructuralFeatures xsi:type="ecore:EReference" name="literals" upperBound="-1"
61 eType="#//EnumLiteral" containment="true"/>
62 <eStructuralFeatures xsi:type="ecore:EReference" name="rawType" eType="#//PrimitiveType"/>
63 </eClassifiers>
64 <!-- EnumLiteral: Enum case -->
65 <eClassifiers xsi:type="ecore:EClass" name="EnumLiteral" eSuperTypes="#//NamedElement">
66 <eStructuralFeatures xsi:type="ecore:EAttribute" name="rawValue" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
67 </eClassifiers>
68 <!-- Property: Class/protocol property -->
69 <eClassifiers xsi:type="ecore:EClass" name="Property" eSuperTypes="#//TypedElement">
70 <eStructuralFeatures xsi:type="ecore:EAttribute" name="visibility" eType="#//VisibilityKind"
71 defaultValueLiteral="public"/>
72 <eStructuralFeatures xsi:type="ecore:EAttribute" name="isReadOnly" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
73 defaultValueLiteral="false"/>
74 <eStructuralFeatures xsi:type="ecore:EAttribute" name="isStatic" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
75 defaultValueLiteral="false"/>
76 <eStructuralFeatures xsi:type="ecore:EAttribute" name="isCollection" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
77 defaultValueLiteral="false"/>
78 <eStructuralFeatures xsi:type="ecore:EAttribute" name="defaultValue" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
79 </eClassifiers>
80 <!-- Operation: Method definition -->
81 <eClassifiers xsi:type="ecore:EClass" name="Operation" eSuperTypes="#//NamedElement">
82 <eStructuralFeatures xsi:type="ecore:EAttribute" name="visibility" eType="#//VisibilityKind"
83 defaultValueLiteral="public"/>
84 <eStructuralFeatures xsi:type="ecore:EAttribute" name="isStatic" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
85 defaultValueLiteral="false"/>
86 <eStructuralFeatures xsi:type="ecore:EAttribute" name="isAsync" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
87 defaultValueLiteral="false"/>
88 <eStructuralFeatures xsi:type="ecore:EAttribute" name="throws" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
89 defaultValueLiteral="false"/>
90 <eStructuralFeatures xsi:type="ecore:EReference" name="returnType" eType="#//Type"/>
91 <eStructuralFeatures xsi:type="ecore:EReference" name="parameters" upperBound="-1"
92 eType="#//Parameter" containment="true"/>
93 </eClassifiers>
94 <!-- Parameter: Method parameter -->
95 <eClassifiers xsi:type="ecore:EClass" name="Parameter" eSuperTypes="#//TypedElement">
96 <eStructuralFeatures xsi:type="ecore:EAttribute" name="label" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
97 <eStructuralFeatures xsi:type="ecore:EAttribute" name="defaultValue" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
98 </eClassifiers>
99</ecore:EPackage>

Section 2

Building the MTL Template

MTL templates define how model elements become text output. We’ll create templates for each UML element type, using AQL expressions to navigate the model and extract information.

The template structure follows a modular approach:

  • Main entry point template

  • Class/struct generation templates

  • Property generation templates

  • Operation generation templates

  • Protocol and enumeration templates

Step 1

Review the complete UML to Swift template with main entry point, generateClassFile, generateProperty, generateOperation, generateProtocolFile, and generateEnumFile templates.

uml2swift.mtl
1[comment encoding = UTF-8 /]
2[module UML2Swift('http://www.example.org/uml')]
3
4[comment]
5 UML to Swift Code Generator
6 Generates Swift source code from UML class diagrams
7[/comment]
8
9[comment ================================================================ /]
10[comment MAIN ENTRY POINT /]
11[comment ================================================================ /]
12
13[template main(pkg : Package)]
14[comment Generate one file per classifier /]
15[for (cls : Class | pkg.classifiers->filter(Class))]
16[generateClassFile(cls)/]
17[/for]
18[for (proto : Protocol | pkg.classifiers->filter(Protocol))]
19[generateProtocolFile(proto)/]
20[/for]
21[for (enum : Enumeration | pkg.classifiers->filter(Enumeration))]
22[generateEnumFile(enum)/]
23[/for]
24[/template]
25
26[comment ================================================================ /]
27[comment CLASS GENERATION /]
28[comment ================================================================ /]
29
30[template generateClassFile(cls : Class)]
31[file (cls.name + '.swift', 'overwrite', 'UTF-8')]
32//
33// [cls.name/].swift
34// Generated from UML model
35//
36
37import Foundation
38
39[if (cls.documentation <> null)]
40/// [cls.documentation/]
41[/if]
42[generateClassDeclaration(cls)/]
43[/file]
44[/template]
45
46[template generateClassDeclaration(cls : Class)]
47[if (cls.isFinal)]final [/if][if (cls.isStruct)]struct[else]class[/if] [cls.name/][generateInheritance(cls)/] {
48
49 // MARK: - Properties
50
51[for (prop : Property | cls.properties)]
52 [generateProperty(prop)/]
53[/for]
54
55 // MARK: - Initialisation
56
57 [generateInitialiser(cls)/]
58
59 // MARK: - Methods
60
61[for (op : Operation | cls.operations)]
62 [generateOperation(op)/]
63[/for]
64}
65[/template]
66
67[template generateInheritance(cls : Class)]
68[if (cls.superClass <> null or cls.protocols->notEmpty())]
69: [if (cls.superClass <> null)][cls.superClass.name/][if (cls.protocols->notEmpty())], [/if][/if][cls.protocols.name->sep(', ')/][/if]
70[/template]
71
72[template generateInitialiser(cls : Class)]
73[let requiredProps = cls.properties->select(p | p.defaultValue = null and not p.isOptional)]
74[if (requiredProps->notEmpty())]
75init([for (p : Property | requiredProps) separator(', ')][p.name/]: [generateTypeName(p)/][/for]) {
76[for (p : Property | requiredProps)]
77 self.[p.name/] = [p.name/]
78[/for]
79 }
80[else]
81init() {
82 }
83[/if]
84[/let]
85[/template]
86
87[comment ================================================================ /]
88[comment PROPERTY GENERATION /]
89[comment ================================================================ /]
90
91[template generateProperty(prop : Property)]
92[if (prop.isStatic)]static [/if][if (prop.isReadOnly)]let[else]var[/if] [prop.name/]: [generateTypeName(prop)/][generateDefaultValue(prop)/]
93[/template]
94
95[template generateTypeName(prop : TypedElement)]
96[if (prop.isCollection)]['[' + prop.type.name + ']'/][else][prop.type.name/][/if][if (prop.isOptional)]?[/if]
97[/template]
98
99[template generateDefaultValue(prop : Property)]
100[if (prop.defaultValue <> null)] = [prop.defaultValue/][elseif (prop.isOptional)] = nil[elseif (prop.isCollection)] = ['[]'/][/if]
101[/template]
102
103[comment ================================================================ /]
104[comment OPERATION GENERATION /]
105[comment ================================================================ /]
106
107[template generateOperation(op : Operation)]
108[if (op.isStatic)]static [/if]func [op.name/]([generateParameters(op)/])[if (op.isAsync)] async[/if][if (op.throws)] throws[/if][generateReturnType(op)/] {
109 // TODO: Implement [op.name/]
110 [generateReturnStub(op)/]
111 }
112[/template]
113
114[template generateParameters(op : Operation)]
115[for (p : Parameter | op.parameters) separator(', ')]
116[if (p.label <> null and p.label <> p.name)][p.label/] [/if][p.name/]: [if (p.isCollection)]['[' + p.type.name + ']'/][else][p.type.name/][/if][if (p.isOptional)]?[/if][if (p.defaultValue <> null)] = [p.defaultValue/][/if][/for]
117[/template]
118
119[template generateReturnType(op : Operation)]
120[if (op.returnType <> null)] -> [op.returnType.name/][/if]
121[/template]
122
123[template generateReturnStub(op : Operation)]
124[if (op.returnType <> null)]
125[if (op.returnType.name = 'String')]return ""
126[elseif (op.returnType.name = 'Int' or op.returnType.name = 'Double')]return 0
127[elseif (op.returnType.name = 'Bool')]return false
128[else]fatalError("Not implemented")
129[/if]
130[/if]
131[/template]
132
133[comment ================================================================ /]
134[comment PROTOCOL GENERATION /]
135[comment ================================================================ /]
136
137[template generateProtocolFile(proto : Protocol)]
138[file (proto.name + '.swift', 'overwrite', 'UTF-8')]
139//
140// [proto.name/].swift
141// Generated from UML model
142//
143
144import Foundation
145
146[if (proto.documentation <> null)]
147/// [proto.documentation/]
148[/if]
149protocol [proto.name/][if (proto.extends->notEmpty())]: [proto.extends.name->sep(', ')/][/if] {
150[for (prop : Property | proto.properties)]
151 var [prop.name/]: [generateTypeName(prop)/] { get[if (not prop.isReadOnly)] set[/if] }
152[/for]
153[for (op : Operation | proto.operations)]
154 func [op.name/]([generateParameters(op)/])[if (op.isAsync)] async[/if][if (op.throws)] throws[/if][generateReturnType(op)/]
155[/for]
156}
157[/file]
158[/template]
159
160[comment ================================================================ /]
161[comment ENUMERATION GENERATION /]
162[comment ================================================================ /]
163
164[template generateEnumFile(enum : Enumeration)]
165[file (enum.name + '.swift', 'overwrite', 'UTF-8')]
166//
167// [enum.name/].swift
168// Generated from UML model
169//
170
171import Foundation
172
173[if (enum.documentation <> null)]
174/// [enum.documentation/]
175[/if]
176enum [enum.name/][if (enum.rawType <> null)]: [enum.rawType.name/][/if] {
177[for (lit : EnumLiteral | enum.literals)]
178 case [lit.name/][if (lit.rawValue <> null)] = [lit.rawValue/][/if]
179[/for]
180}
181[/file]
182[/template]

Section 3

Sample UML Model

We’ll use a Task Manager application model to demonstrate the code generator. This model includes:

  • A struct (Task) with various properties

  • A class (Project) with async methods

  • Protocols (Identifiable, TaskRepository)

  • Enumerations (Priority, Status)

Step 1

Examine the sample UML model.

The model defines a complete Task Manager domain with proper Swift types, optionality, collections, and method signatures including async/throws.

sample-model.xmi
1<?xml version="1.0" encoding="UTF-8"?>
2<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
3 xmlns:uml="http://www.example.org/uml">
4 <!-- Sample UML Model: Task Management Application -->
5 <uml:Package name="TaskManager">
6 <!-- Primitive Types -->
7 <classifiers xsi:type="uml:PrimitiveType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="String"/>
8 <classifiers xsi:type="uml:PrimitiveType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Int"/>
9 <classifiers xsi:type="uml:PrimitiveType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Bool"/>
10 <classifiers xsi:type="uml:PrimitiveType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Date"/>
11
12 <!-- Identifiable Protocol -->
13 <classifiers xsi:type="uml:Protocol" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Identifiable"
14 documentation="A type with a unique identifier">
15 <properties name="id" isReadOnly="true" type="//@classifiers.0"/>
16 </classifiers>
17
18 <!-- Priority Enumeration -->
19 <classifiers xsi:type="uml:Enumeration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Priority"
20 documentation="Task priority levels" rawType="//@classifiers.1">
21 <literals name="low" rawValue="0"/>
22 <literals name="medium" rawValue="1"/>
23 <literals name="high" rawValue="2"/>
24 <literals name="critical" rawValue="3"/>
25 </classifiers>
26
27 <!-- Status Enumeration -->
28 <classifiers xsi:type="uml:Enumeration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Status"
29 documentation="Task status values">
30 <literals name="pending"/>
31 <literals name="inProgress"/>
32 <literals name="completed"/>
33 <literals name="cancelled"/>
34 </classifiers>
35
36 <!-- Task Class (struct) -->
37 <classifiers xsi:type="uml:Class" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Task"
38 documentation="Represents a task in the system" isStruct="true">
39 <protocols>//@classifiers.4</protocols>
40 <properties name="id" isReadOnly="true" type="//@classifiers.0"/>
41 <properties name="title" type="//@classifiers.0"/>
42 <properties name="description" isOptional="true" type="//@classifiers.0"/>
43 <properties name="priority" type="//@classifiers.5" defaultValue=".medium"/>
44 <properties name="status" type="//@classifiers.6" defaultValue=".pending"/>
45 <properties name="dueDate" isOptional="true" type="//@classifiers.3"/>
46 <properties name="tags" isCollection="true" type="//@classifiers.0"/>
47 <operations name="isOverdue" returnType="//@classifiers.2">
48 <parameters name="currentDate" type="//@classifiers.3"/>
49 </operations>
50 <operations name="markComplete">
51 </operations>
52 </classifiers>
53
54 <!-- Project Class -->
55 <classifiers xsi:type="uml:Class" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Project"
56 documentation="A project containing multiple tasks">
57 <protocols>//@classifiers.4</protocols>
58 <properties name="id" isReadOnly="true" type="//@classifiers.0"/>
59 <properties name="name" type="//@classifiers.0"/>
60 <properties name="tasks" isCollection="true" type="//@classifiers.7"/>
61 <properties name="isActive" type="//@classifiers.2" defaultValue="true"/>
62 <operations name="addTask">
63 <parameters name="task" type="//@classifiers.7"/>
64 </operations>
65 <operations name="removeTask">
66 <parameters name="taskId" type="//@classifiers.0"/>
67 </operations>
68 <operations name="tasksWithPriority" returnType="//@classifiers.7" isCollection="true">
69 <parameters name="priority" type="//@classifiers.5"/>
70 </operations>
71 <operations name="fetchRemoteTasks" isAsync="true" throws="true"/>
72 </classifiers>
73
74 <!-- TaskRepository Protocol -->
75 <classifiers xsi:type="uml:Protocol" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="TaskRepository"
76 documentation="Protocol for task persistence">
77 <operations name="save" throws="true">
78 <parameters name="task" type="//@classifiers.7"/>
79 </operations>
80 <operations name="findById" returnType="//@classifiers.7" isOptional="true">
81 <parameters name="id" type="//@classifiers.0"/>
82 </operations>
83 <operations name="findAll" returnType="//@classifiers.7" isCollection="true"/>
84 <operations name="delete" throws="true">
85 <parameters name="id" type="//@classifiers.0"/>
86 </operations>
87 </classifiers>
88 </uml:Package>
89</xmi:XMI>

Section 4

Generated Swift Code

Running the template produces multiple Swift files, one for each classifier. Let’s examine the generated output to understand how UML elements map to Swift code.

Step 1

Examine the generated Identifiable protocol.

Protocols generate property requirements with get/set accessors and method requirements preserving async/throws modifiers.

Identifiable.swift
1//
2// Identifiable.swift
3// Generated from UML model
4//
5
6import Foundation
7
8/// A type with a unique identifier
9protocol Identifiable {
10 var id: String { get }
11}

Step 2

Examine the generated Priority enumeration.

Enumerations generate cases with optional raw values. The raw type is determined from the enumeration’s attributes.

Priority.swift
1//
2// Priority.swift
3// Generated from UML model
4//
5
6import Foundation
7
8/// Task priority levels
9enum Priority: Int {
10 case low = 0
11 case medium = 1
12 case high = 2
13 case critical = 3
14}

Step 3

Examine the generated Task struct.

Structs include MARK comments for organisation, properties with proper types and default values, memberwise initialisers, and method stubs.

Task.swift
1//
2// Task.swift
3// Generated from UML model
4//
5
6import Foundation
7
8/// Represents a task in the system
9struct Task: Identifiable {
10
11 // MARK: - Properties
12
13 let id: String
14 var title: String
15 var description: String? = nil
16 var priority: Priority = .medium
17 var status: Status = .pending
18 var dueDate: Date? = nil
19 var tags: [String] = []
20
21 // MARK: - Initialisation
22
23 init(id: String, title: String) {
24 self.id = id
25 self.title = title
26 }
27
28 // MARK: - Methods
29
30 func isOverdue(currentDate: Date) -> Bool {
31 // TODO: Implement isOverdue
32 return false
33 }
34
35 func markComplete() {
36 // TODO: Implement markComplete
37 }
38}

Step 4

Examine the generated Project class.

Classes support inheritance (protocol conformance), async/throws methods, and proper access modifiers based on UML visibility.

Project.swift
1//
2// Project.swift
3// Generated from UML model
4//
5
6import Foundation
7
8/// A project containing multiple tasks
9class Project: Identifiable {
10
11 // MARK: - Properties
12
13 let id: String
14 var name: String
15 var tasks: [Task] = []
16 var isActive: Bool = true
17
18 // MARK: - Initialisation
19
20 init(id: String, name: String) {
21 self.id = id
22 self.name = name
23 }
24
25 // MARK: - Methods
26
27 func addTask(task: Task) {
28 // TODO: Implement addTask
29 }
30
31 func removeTask(taskId: String) {
32 // TODO: Implement removeTask
33 }
34
35 func tasksWithPriority(priority: Priority) -> Task {
36 // TODO: Implement tasksWithPriority
37 fatalError("Not implemented")
38 }
39
40 func fetchRemoteTasks() async throws {
41 // TODO: Implement fetchRemoteTasks
42 }
43}

Step 5

Examine the generated TaskRepository protocol.

Repository protocols define CRUD operations with proper parameter types and return types.

TaskRepository.swift
1//
2// TaskRepository.swift
3// Generated from UML model
4//
5
6import Foundation
7
8/// Protocol for task persistence
9protocol TaskRepository {
10 func save(task: Task) throws
11 func findById(id: String) -> Task?
12 func findAll() -> [Task]
13 func delete(id: String) throws
14}

Section 5

Running the Generator

Execute the MTL template to generate Swift code from the UML model. The output creates one file per classifier in the output directory.

Step 1

Run the code generator.

Execute swift-mtl with the template and model. Each classifier produces a separate Swift file with proper naming and structure.

Terminal
1# Run the UML to Swift code generator
2swift-mtl generate \
3 --template uml2swift.mtl \
4 --metamodel uml-class.ecore \
5 --model sample-model.xmi \
6 --output ./generated/
7
8# Output:
9# Generating Swift code from UML model...
10# Created: generated/Identifiable.swift
11# Created: generated/TaskRepository.swift
12# Created: generated/Priority.swift
13# Created: generated/Status.swift
14# Created: generated/Task.swift
15# Created: generated/Project.swift
16# Generation complete: 6 files created

Check Your Understanding

Question 1 of 3

How does the template determine whether to generate a struct or class?

Question 2 of 3

What AQL expression would get all required properties (non-optional) of a class?

Question 3 of 3

Why does each classifier get its own output file?