Skip to content

Instantly share code, notes, and snippets.

View IanKeen's full-sized avatar
🏂

Ian Keen IanKeen

🏂
View GitHub Profile
@IanKeen
IanKeen / EntryPoint.swift
Last active March 13, 2025 00:22
Example main.swift
import Foundation
import SwiftUI
let isUITesting = /* your UI test detection here */
@main
struct EntryPoint {
static func main() {
if isUITesting {
UITestApp.main()
@IanKeen
IanKeen / DynamicProperties.swift
Created February 19, 2025 19:16
Support stored properties in extensions
public protocol DynamicProperties: AnyObject {
subscript<T>(dynamic key: String) -> T? { get set }
}
private extension String {
var unsafePointer: UnsafeRawPointer {
return UnsafeRawPointer(bitPattern: hashValue)!
}
}
extension DynamicProperties {
@IanKeen
IanKeen / AnalyticsReducer.swift
Created January 16, 2024 04:27
TCA: Example of creating an Analytics component to get before/after state
public protocol AnalyticsReducer {
associatedtype State
associatedtype Action
func analytics(before: State, after: State, action: Action) -> Effect<Action>
}
public struct _AnalyticsReducer<Base: Reducer, Analytics: AnalyticsReducer>: Reducer where Analytics.State == Base.State, Analytics.Action == Base.Action {
@usableFromInline
let base: Base
@IanKeen
IanKeen / EnvironmentValues.swift
Last active February 8, 2025 23:16
SwiftUI: Peek at/extract hidden environment values
import Foundation
import SwiftUI
extension EnvironmentValues {
public func value<T>(_: T.Type = T.self, forKey key: String) -> T? {
guard let value = first(where: { name($0, equals: key) }) else {
print("No EnvironmentValue with key '\(key)' found.")
return nil
}
@IanKeen
IanKeen / UserDefaultsKey.swift
Last active December 24, 2024 23:12
Simple type safe wrapper around UserDefaults
struct UserDefaultsKey<T: Codable> {
var name: String
var `default`: T
}
extension UserDefaults {
func get<T>(_ key: UserDefaultsKey<T>) -> T {
guard
let data = data(forKey: key.name),
let box = try? JSONDecoder().decode(Box<T>.self, from: data)
@IanKeen
IanKeen / AllowDecodingFailure.swift
Created October 3, 2024 18:36
PropertyWrapper: AllowDecodingFailure will catch decoding errors and return `nil` rather than failing the operation
@propertyWrapper
public struct AllowDecodingFailure<T: Codable>: Codable {
public var wrappedValue: T?
public var error: Error?
public var projectedValue: AllowDecodingFailure<T> { self }
public init(wrappedValue: T?) {
self.wrappedValue = wrappedValue
self.error = nil
}
@IanKeen
IanKeen / Abstraction.swift
Created August 16, 2022 17:41
TCA Scoping Abstraction
// MARK: - TCAView
public protocol TCAView: View where Body == WithViewStore<ScopedState, ScopedAction, Content> {
associatedtype ViewState
associatedtype ViewAction
associatedtype ScopedState
associatedtype ScopedAction
associatedtype Content
@IanKeen
IanKeen / ObservableAppStorage.swift
Created October 10, 2024 17:06
PropertyWrapper: ObservableAppStorage - Make UserDefaults work with @observable models (without all the boilerplate)
import Observation
public protocol _Observable: Observable {
nonisolated
func _access<Member>(keyPath: KeyPath<Self, Member>)
nonisolated
func _withMutation<Member, MutationResult>(
keyPath: KeyPath<Self, Member>,
_ mutation: () throws -> MutationResult
@IanKeen
IanKeen / Debounce.swift
Created January 16, 2019 19:13
Simple debouncer
func debounce<T>(delay: TimeInterval, function: @escaping (T) -> Void, complete: @escaping () -> Void = { }) -> (T) -> Void {
let queue = DispatchQueue(label: "Debouncer")
var current: DispatchWorkItem?
return { input in
current?.cancel()
let new = DispatchWorkItem {
function(input)
complete()
}
@IanKeen
IanKeen / Partial.swift
Last active September 10, 2024 11:59
Partial<T>
/// A wrapper for a partial representation of a `T`.
/// It can be constructed over time, then later used to
/// build a complete `T`
@dynamicMemberLookup
public struct Partial<T> {
enum Error: Swift.Error {
case invalid(PartialKeyPath<T>)
}
// MARK: - Private Properties