Skip to content

Instantly share code, notes, and snippets.

View colinfwren's full-sized avatar

Colin Wren colinfwren

View GitHub Profile
@colinfwren
colinfwren / ExampleServiceTest.swift
Created January 24, 2025 23:54
An example of tests using the mock
import Testing
@testable import ExampleApp
@Suite("Example Service Test") struct ExampleServiceTest {
@Test("Restores from UserDefaults") func restoreValues() throws {
// setup
let classToBeStored = SomeClass(foo: "bar")
let dataToStore = try? JSONEncoder().encode(classToBeStored)
let mockUserDefault = MockUserDefault()
@colinfwren
colinfwren / MockUserDefaults.swift
Last active January 24, 2025 23:41
Mock of UserDefaults
class MockUserDefault: UserDefaults {
var persistedValue: Data? = nil
var persistedKey: String? = nil
override func set(_ value: Any?, forKey defaultName: String) {
persistedValue = value as? Data
persistedKey = defaultName
}
override func object(forKey defaultName: String) -> Any? {
@colinfwren
colinfwren / ExampleServicer.swift
Last active January 24, 2025 23:45
An example service that reads from UserDefaults on init
class ExampleService {
private let userDefaults: UserDefaults
var aStoredClass: SomeClass
init(userDefaults: UserDefaults) {
self.userDefaults = userDefaults
if let serialisedObject = self.userDefaults.object(forKey: "someKey") as? Data {
if let storedClass = try? JSONDecoder().decode(SomeClass.self, from: serialisedObject) {
self.aStoredClass = storedClass
} else {
@colinfwren
colinfwren / mockingUserDefaults.swift
Created January 18, 2025 22:54
Creating a mock UserDefaults
import Testing
import Foundation
@testable import ExampleApp
class MockUserDefaults: UserDefaults {
var persistedData: Data? = nil
var persistedKey: String? = nil
override func set(_ value: Any?, forKey defaultName: String) {
persistedData = value as? Data
@colinfwren
colinfwren / ServiceTests.swift
Last active January 18, 2025 22:45
Unit tests for service
import Testing
import Foundation
import SwiftData
@testable import ExampleApp
@Suite("Example Service Test") struct ExampleServiceTest {
let someOtherModelDescriptor = FetchDescriptor<SomeOtherModel>(sortBy: [SortDescriptor(\SomeOtherModel.created, order: .reverse)])
@MainActor @Test("Adding SomeModel record when have SomeOtherModel record") func addRecordWithExisting() throws {
@colinfwren
colinfwren / ViewUsingService.swift
Last active January 18, 2025 22:30
SwiftUI View using the Service
import SwiftUI
struct ContentView: View {
@EnvironmentObject private var exampleService: ExampleService
var body: some View {
List {
ForEach(exampleSerivce.someList, id: \.self) { listItem in
Text(listItem.name)
}
@colinfwren
colinfwren / AppWithService.swift
Created January 18, 2025 22:19
Exposing service as an environment object
import SwiftUI
import SwiftData
@main
struct ExampleApp: App {
private let exampleService: ExampleService
let sharedModelContainer: ModelContainer
init() {
let schema = Schema([
@colinfwren
colinfwren / ExampleService.swift
Last active January 18, 2025 22:39
An example of the Service pattern in Swift
import SwiftData
// Ensure the service conforms to the ObservableObject protocol
class ExampleService: ObservableObject {
private let modelContext: ModelContext
@Published var someList = [SomeModel]() // The published decorator for properties that should trigger SwiftUI updates
// Pass the modelContext in to the initialiser so can use dependency injection during testing
init(modelContext: ModelContext) {
self.modelContext = modelContext
@colinfwren
colinfwren / UXImprovedDataExportButton.swift
Last active January 10, 2025 22:38
Data Export Button with UX improvements
import SwiftUI
import SwiftData
struct DataExportButton: View {
@Environment(\.modelContext) var modelContext
@State private var generatingExport = false
@State private var showExportError = false
@Binding var sharingExport: Bool = false
@Binding var exportUrl: URL?
@colinfwren
colinfwren / DataExportButtonAndParent.swift
Last active January 10, 2025 22:38
Hoisting the ShareSheet into parent view
import SwiftUI
import SwiftData
struct ContentView: View {
@State var showingDataExportSheet: Bool = false
@State var exportUrl: URL?
var body: some View {
DataExportButton(sharingExport: $showingDataExportSheet, exportUrl: $exportUrl)
.sheet(isPresented: $showingDataExportSheet) {