Category Archives: Swift

Swift Protocols, Structs and Classes

Note: I’m going through draft posts that go back to 2014 and publishing where they still may have value. They may not be 100% upto date but better published late than never.

Introduction

Protocols can be thought of as similar to interfaces within languages such as C# and Java, hence are used to declare expectations for implementations and can be returned or accepted as params.

We declare a protocol in the following way

protocol Person {
  var firstName: String { get }
  var lastName: String { get }
  var age: Int { get }
}

So we can create our implementation of this procotol like this

struct PersonImpl : Person {
  var firstName: String
  var lastName: String
  var age: Int
}

Structs and Classes

Apple Swift developers seem to prefer value types over reference types, a struct is a value type and class a reference type. They both share many of the same functionality.

Structs do not require an initializer (constructor) as a default initializer is supplied automatically and will expect all non-optional properties to be supplied.

class PersonImpl : Person {
  var firstName: String
  var lastName: String
  var age: Int

  init(firstName: String, lastName: String, age: Int) {
    self.firstName = firstName
    self.lastName = lastName
    self.age = age
  }
}

As you can see, init is the name of the initializer or what we may view as a constructor. Classes may also have deinit is called when Swift deallocates an instance (struct’s do not have deinit).

Mutations

Where we expect changes to the internal data, in other words where a function mutates data we use the mutating keyword. If, for example, we add a protocol function

func incrementAge() -> Void // same as func incrementAge()

By default struct properties cannot be changed by instance method. In such cases we need to include the mutating key word, i.e.

mutating func incrementAge() -> Void

So a struct method implementation will now look like this

mutating func incrementAge() -> Void {
  age += 1
}

Within a class, we don’t need to mark the method as mutating.

Accessors

There are five access levels

  • Open: This allows proprties, methods, classes etc. to be accessible by anything that imports the module
  • Public: This allows proprties, methods, classes etc. to be accessible by anything that imports the module
  • Internal: This is the default access level and allows properties, methods, classes etc. to be accessible from the module where they’re defined only
  • Fileprivate: Properties and methods can access from code withint he same source file only
  • Private: The least visible accessor meaning properties methods etc. are only visible within the same file or class etc.

is and as

Swift has the concept of is and as pretty much like C#. So we can declare a type as follows

let p: Person = PersonImp("Scooby", "Doo", "12")

Now if we needed to check if the const p is a PersonImpl we would use

if p is PersonImpl {    
}

we could use as within the if statement if we wanted as well, for example

if let person = p as? PersonImpl {    
}

Here we compare and assign in the same line of code using as? which basically means the person may be nil (if the type cannot be converted to PersonImpl).

Extensions

Just like extension classes in C# – Swift extensions allow us to add functionality to structures, protocols and classes (as well as enumerations).

An extension is defined using the extension key word, for example

extension String {
  // add string functionality, for example
  func capitalize() -> String {
    return self[0].toUpper() + self.substr(1)
  }
}

We can also add constraints to extensions, so for example a Collection extension that

extension Collection where Iterator.Element: Comparable {
  // add functionality where elements support Comparable
}

Equatable

A type needs to conform to the Equatable protocol for a type to be comparable using == and !=.

Generics

Swift generics look much the same as generics in C++, Java and C# in that we can declare generics on a function like this

func add<T>(item: T) {
}

We can also add constraints to the genric type like this

func compare<T: Comparable>(a: T, b: T) -> Bool {
}

Experiments with Swift Generics

Note: I’m going through draft posts that go back to 2014 and publishing where they still may have value. They may not be 100% upto date but better published late than never.

Generics are interesting within Swift. Syntactically they look the same as most other languages which supports generics. So, we have the syntax below

class Policy<TResult> {
}

Generic and non-generic types of the same name

In C# we can essentially create a generic and non generic type and the compiler works out which we meant to use. Sadly this doesn’t exist in Swift (or Java or maybe many other implementations). But then, rather interestingly we can (assuming no constraint on the generic parameter) actually create a generic of type Void, i.e.

class Test<TResult> {
  func run(_ action: () -> TResult) -> TResult {
    return action()
  }
}

and then write code like this

let a1 = Test<String>()
let a2 = a1.run({ return "Hello" })

let b1 = Test<Void>()
let b2 = b1.run({ return })

What about, if we looked at this problem from the perspective of creating a default type for the generic. Swift doesn’t support this but we can (sort of) create something like this using init. Where we take an argument of the generic type, so for example if we have

class Test<T> {
  init(value: T) {
  }
}

Okay so we can now declare our variables like this

let t1 = Test(value: 42)
let t2 = Test(value: "Hello")

I know, this doesn’t have a default implementation at all, so instead we’ll create an extension which does the defaulting for us

extension Test where T == Person {
    convenience init() {
        self.init(value: Person())
    }
}

Now we create an instance like this

let t3 = Test()

See Can I assign a default type to generic type T in Swift? for further information on this one.

Adding constraints

We can add a constraint, for example the generic type must a a type of Error, like this

class Test<TError: Error> {
}

We can also create constraints against properties of a type, for example at a function level we can check or (as above) on extensions using the where clause. So in the example

extension Test where T == Person {
}

The extension implicitly knows that there’s a generic parameter T and so we don’t need to redeclare it, instead we’re simply saying this extension works for Test where T is a Person. This sort of technique can also be used within functions.

Default value

If you come from a C# background, you’ll probably be used to using default(T) or the shortened version simply default. Swift doesn’t include such a keyword. Instead you’ll either need to use optionals, i.e. returned a .some or .none, or ofcourse you might create a function of class to imitate such functionality yourself.

Swift async/await

Note: I’m going through draft posts that go back to 2014 and publishing where they still may have value. They may not be 100% upto date but better published late than never.

Swift comes with async/await syntax/functionality, however the support is dependent upon version of Swift and more importantly whether it’s the Mac (I’ll include iOS and watch OS in this) version of the Linux version.

Currently I’m playing with Swift on Linux and using the URLSession.shared.dataTask which is essentially a callback function. The URLSession.shared.data async/await version currently does not exist on Linux. So let’s create our own version and look at the process and ofcourse, how to use async/await (if you’ve used C#, TypeScript with async/await you’ll already know the basics of using the syntax).

Functions should be declared as async, so for example

func data(for request: URLRequest) async -> (Data, URLResponse) {
  // do something
}

Here’s an example of using the URLSession.shared.dataTask and declaring the code in an async method

#if canImport(FoundationNetworking)
public extension URLSession {
    func data(for request: URLRequest) async -> (Data, URLResponse) {
        await withCheckedContinuation { continuation in
            URLSession.shared.dataTask(with: request) { data, response, error in
                continuation.resume(returning: (data!, response!))
            }.resume()
        }
    }
}
#endif

Now, in usage, we can do this

let data = await URLSession.shared.data(for: request)

Structs and Classes in Swift

I’ve previously posted about structs and classes in Swift, let’s look a little more in depth into the subject

Differences between a struct and class

As you may know, structs use value semantics whilst classes use reference semantics. In other words if you do something like this

struct Point {
   var x: Double
   var y: Double
}

let pt1 = Point(x: 1, y: 10)
let pt2 = pt1

Your pt1.x, pt1.y values are copied to pt2.x, pt2.y. If you therefore alter p1 this does no affect p2. Swift using COW (copy on write) so this is more performant than one might think if you were making lots of copies – in other words the copying takes place only when a value is changed – so thing lazy copying of values.

Structs are stored on the stack and hence are very performant in terms of creation etc. Ofcourse if you’re making many changes to copies of a struct then things are less performant due to all the copying that needs to happen (even with COW).

Ofcourse, in a more complicated scenario, such as the Point also having a member variable which is a class, then these will be stored on the stack, but with references to the heap based classes. This is an issue for structs, if a struct contain multiple reference types it’ll incur reference counting for each reference type in the struct.

Classes on the other hand use reference semantics and therefore if we rewrite the about for a class. Then p2 is a reference to p1. Any changes to p1 will be reflected in p2

class Point {
   var x: Double
   var y: Double
}

let pt1 = Point(x: 1, y: 10)
let pt2 = pt1

Classes are stored on the heap which means that allocation will be les performant than a struct, but ofcourse if you’re passing around a reference to a class, this is more performant. However because a reference type copies the reference pointer it does ofcourse lend itself to issues around mutation of state and this becomes more of an issue when we add in concurrency.

The reference types use reference counting to handle auto-deletion (i.e. garbage collection). This does mean that a reference type will also require more space that a struct to track it’s reference counter. Also due to it using the heap, again potential concurrency issues means the OS must lock memory etc.

If you’re using String or the likes in a struct, you’re storing a reference type, hence this will incur reference counting overhead. If we’re using a String to ultimately represent known values, for example UP, DOWN, OUT_OF_SERVICE then not only will it be more type safe to use an enum, from a performance perspective this would be better, for example we can declare a status enum with a String type as a raw backing value like this

enum Status: String {
   case up = "UP"
   case down = "DOWN"
   case outOfService = "OUT_OF_SERVICE"
}

Swift’s @discardableResult

When we’re writing Swift code we might have a function that returns a value as part of its invocation. For example, maybe we’ve a function which sends some data to a server and then returns a boolean to denote success or failure, here’s a mock up

func serviceCall() -> Bool {
    // do something real here
    true
}

We call this method but maybe we don't care what the result is, so we simply call it like this

[code]
serviceCall()

If we build this, swift will report warning: result of call to ‘serviceCall()’ is unused serviceCall(). We can get around this using a discard, for example

let _ = serviceCall()
// OR
_ = serviceCall()

but there’s another way to tell the compiler to ignore this warning. We mark the function with the @discardableResult attribute, i.e.

@discardableResult
func serviceCall() -> Bool {
    // do something real here
    true
}

Admittedly this seems a little odd, that the function being called should say, “hey you can just ignore the result”. This is something that should probably be used with care, although if it’s known that the function’s result is likely to be ignored, then it’s better than having lots of discards all over the place to ignore the result of the function.

Conditional Compilation with Swift

Occasional you’ll need to write code blocks that are specific to an OS (as I’ve found Swift on Linux and on Mac OS is not always 100% in sync with features).

In which case we can use conditional compilation blocks, such as

#if os(Linux)
// code specific to Linux
#elseif os(Windows)
// code specific to Windows
#endif

The os() condition accepts, macOS, iOS, watchOS, tvOS, Linux and Windows.

Other conditions include architecture arch() with options i386, x86_64, arm and arm64.

Swift also allows supports canImport which can be used to check if a module is available, like this

#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

See Conditional Compilation Block from the Swift language manual for a full list of conditions.

Swift unit tests, including and using .json files

Note: I’m running everything on Ubuntu 20.0.4 using Swift version 5.7.1. I’m assuming everything listed below works on Mac etc. as well.

I have a simple Eureka client package (named SwiftEureka) that I’ve been working on. Now I’ve tested it against a running instance of Eureka but I want to write some unit tests where I don’t need the server running. The idea simply being that I have a bunch of .json files which contain the JSON responses, taken from Eureka, for various REST calls.

So, to summarise, I basically want to have .json files within my Tests folder and use them within my unit tests.

Let’s assume we have our Tests/EurekaTests folder and within that we have a file named applications.json. We need to add this to the Package.swift file under the .testTarget section, like this

.testTarget(
   name: "EurekaTests",
   dependencies: ["SwiftEureka"],
      resources: [
         .process("applications.json")
      ]),

Now the file will be seen by Swift as part of the package’s bundle.

Next, we need to load the file into our tests. We do this by using the Bundle object, like this

guard let path = Bundle.module.url(forResource: "applications", withExtension: "json") else {
   XCTFail("Missing file: applications.json")
   return
}

let json = try Data(contentsOf: path)
let wrapper = try JSONDecoder().decode(ApplicationsWrapper.self, from: json)

Swift Tasks

Swift uses the Task struct to execute code concurrently. We can run a Task and await the return value or we can use in a “fire and forget” manner. We create a task like this

Task {
   // do something
}

We do not need to call a start method or the likes, once created the code starts. If you intend to return a value you’d write something like this

let result = await Task { () -> String in
   "Hello World"
}.value

Ofcourse we might also have the possibility of throwing an exception, hence we’d use

do {
   let result = try await Task { () -> String in
      throw MyError.failed
   }.value
} catch {
}

Properties, Binding, Property Wrappers and MVVM with Swift

Swift includes properties within the language (see Properties), but also supports (what we’d call in C#) property or data binding mechanisms.

Before we get started, I’m writing this post as a learning exercise, I’d suggest you checkout the references at the bottom of the post for a much more in depth look at this subject.

If you’re still reading, then let’s get started…

To begin with we’ll look at how we declare properties in Swift first. For those coming from C# or similar languages, then the simplest stored property looks just like a field

Property Declarations

struct MyModel {
    var id: String;
}

The above declaration is known as a stored property, in that we can store values with the specific instance of the MyModel type, this is really the equivalent of having a property with a default getter and setter.

We can also declare properties as readonly like this

struct MyModel {
    var id: String {
        return "SomeId"
    }
}

Both of the above examples are basically properties using “shorthand syntax”, like C# we can also create properties with get and set keywords – of course these are useful if the setting of the property (for example) does more than just assign a value, hence we have a form (notice you can use return or in these example we’re using implicit return

struct MyModel {
    private var _id: String = "SomeId"
        
    var id: String {
        get {
            _id
        }
        set {
            _id = newValue
        }
    }
}

Property Observer

Property observers allow us to monitor a property change. For example if you have a struct/class with the shorthand syntax for a property then we can willSet and/or didSet to our property, for example

struct MyModel {
    var id: String = "" {
        willSet(newTitle) {
            print("About to set value")
        }
        didSet {
            if title != oldValue {
                print("Set Value")
            }
        }
    }
}

Now when the property is about to be set, the willSet code is called and when a value changes didSet will be called. Obviously you wouldn’t want to do anything within these methods that could affect performance.

Property Wrapper

A Property Wrapper allows us to (well as the name suggests) wrap a property within a type that we can separate the storage of the property from functionality that acts upon that property. For example if our title has a length constraint, we might create a property wrapper to implement this functionality

@propertyWrapper
struct LengthConstraint {
    private var value = ""
    var wrappedValue: String {
        get { value }
        set { value = String(newValue.prefix(5)) }
    }
}

Property Binding

So what’s this got to do with binding/data binding/property binding? Well we’ve now seen how we declare propeties and can add property wrappers to the property. Within SwiftUI we can use the @Published property wrapper to our property which gets observed by a UI element and when the value changes updates the UI or in the case of TextField, when changes are made to the text field it’s placed into our property.

There are several different property wrappers for this type of functionality

  • @Published – this is used on property classes, such as ObservableObject subclasses.
  • @StateObject – this is used within a view to store an instance of an ObservableObject subclassed type
  • @State – this allows us to store bindable data within a view
  • @Binding – this is used in views which need to mutate a property owned by an ancestor view. In essences it’s like connecting to a parent’s property
  • @EnvironmentObject – this is a shared object stored within the environment and is used in situations where passing properties through a UI hierarchy or the likes becomes too cumbersome.
  • @Environment – this is used to connect to actual environment properties, such as reading whether the application is in dark theme or other SwiftUI properties

MVVM

We can declares @State and @Binding property wrappers (for example) within our view, but of course this can pollute the UI with view model state. If we prefer to go with a MVVM approach, i.e. separate the view from the view model, then we will start off by subclassing ObservableObject, for example here’s a minimal view model

@MainActor class ViewModel: ObservableObject {
    @Published var title: String = ""
}

@StateObject private var viewModel = ViewModel()

In the above code we declare and subclass of the ObservableObject and then we declare the properties that we wish to expose. The @StateObject line is what you’ll have in your ContentView to create an instance of the ObservableObject.

The @MainActor is used to denote that this class runs code on the main queue – essentially if you’re used to Windows UI programming this can be seen as equivalent to running code on the UI thread.

This of course might seem simpler to just declare properties like this, but then our model ends up more tightly coupled to the view than we might want

@State var title: String = ""

References

All SwiftUI property wrappers explained and compared
How to use @MainActor to run code on the main queue
What is the @Environment property wrapper?

Unit testing with Swift

Unit test classes in Swift derive from XCTestCase. You’ll need to import XCTest.

So for example

import XCTest

class MvvmTestTests: XCTestCase {
}

Test functions need to be prefixed with test so for example, if we assume we have a global function like this

func add(_ a: Int, _ b: Int) -> Int {
    return a + b
}

then we might have a test like this

func testAdd() throws {
    XCTAssertEqual(5, MyApp.add(2, 3))
}

Before we can test our add function we need to make the application code available to the test code, to do this after the import XCTest line add

@testable import MyApp

This actually allows our tests to access our code without having to mark all the code as public.

As you’ve seen we use XCTAssertEqual to assert our expectations against actual.

Measuring Performance

We can wrap our code, within a test, using

self.measure {
}

So for example (whilst a little pointless on our add function) we can measure performance like this

self.measure {
   _  = MvvmTest.add(2, 3)
}

We can also apply options to the measure function

let option = XCTMeasureOptions()
option.iterationCount = 100
self.measure(options: option) {
    _  = MvvmTest.add(2, 3)
}

In this case we’ll run the measure block 100 + 1 times. The iteration actually ignores the first run (hence the + 1) this tries to remove cold start times.

Running our tests

In Xcode, select the Test Navigator, this should show you all the tests found. Simply select either a single test or group of tests and right mouse click. Select the Run option and your tests will run.