Skip to content

Instantly share code, notes, and snippets.

View IanKeen's full-sized avatar
🏂

Ian Keen IanKeen

🏂
View GitHub Profile
@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 / 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 / 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 / AllowDecodingFailures.swift
Created June 14, 2024 17:25
PropertyWrapper: Allows for single elements in an array to "fail" decoding without failing the entire operation
@propertyWrapper
public struct AllowDecodingFailures<T: Codable>: Codable {
public var wrappedValue: [T]
public var errors: [Error]
public var projectedValue: AllowDecodingFailures<T> { self }
private struct Empty: Decodable { }
public init(wrappedValue: [T]) {
self.init(wrappedValue: wrappedValue, errors: [])
@IanKeen
IanKeen / AsyncPublished.swift
Created May 21, 2024 17:58
PropertyWrapper: AsyncPublished
@propertyWrapper @MainActor public struct AsyncPublished<Value> {
public typealias AsyncAction = (Value) async throws -> Void
private class State {
var wrappedValue: Value
var isWorking: Bool = false
var current: Task<Void, Never>?
var action: AsyncAction = { _ in fatalError("Please configure action in parent object") }
init(wrappedValue: Value) {
@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 / ReadSpacing.swift
Created October 24, 2022 20:10
SwiftUI: Read the default spacing for use elsewhere
struct ReadSpacing<Content: View>: View {
@State private var spacing: CGFloat = 0
@Binding private var outsideSpacing: CGFloat?
private let content: (CGFloat) -> Content
init(@ViewBuilder content: @escaping (CGFloat) -> Content) {
self._outsideSpacing = .constant(nil)
self.content = content
}
init(into spacing: Binding<CGFloat>, @ViewBuilder content: @escaping () -> Content) {
@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 / Invalidating.swift
Created July 31, 2022 01:36
PropertyWrapper: @invalidating backport
struct Invalidation {
static let display = Invalidation { $0.setNeedsDisplay() }
static let layout = Invalidation { $0.setNeedsLayout() }
let action: (UIView) -> Void
}
@propertyWrapper
struct Invalidating<Value> {
private let invalidations: [Invalidation]
@IanKeen
IanKeen / .swift
Created July 26, 2022 22:33
SwiftUI: @StateObject.init(wrappedValue:) gotcha
struct Parent: View {
@State private var foo = "foo" {
didSet { print("Parent", foo) }
}
var body: some View {
VStack {
Inner(value: foo)
Button("Parent Double") {