Skip to content

Instantly share code, notes, and snippets.

View IanKeen's full-sized avatar
🏂

Ian Keen IanKeen

🏂
View GitHub Profile
@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 March 30, 2026 23:02
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 / LoadingIndicator.swift
Last active March 24, 2026 10:07
SwiftUI: Drop-in Pull to Refresh mechanism
public struct LoadingIndicator: View {
@State private var startingOffset: CGFloat = 0
@State private var space: CGSize = .zero
@State private var size: CGSize = .zero
@State private var progress: Double = 0
@Binding private var isLoading: Bool {
didSet {
if isLoading { action() }
else { progress = 0 }
}
@IanKeen
IanKeen / Require.swift
Last active March 24, 2026 10:06
SwiftUI: Conditional views from optional bindings with required constraints
public struct Require<Content: View>: View {
@StateObject private var registrar: ViewRegistrar
@ViewBuilder private var content: () -> Content
public init(_ value: Int, @ViewBuilder content: @escaping () -> Content) {
self._registrar = .init(wrappedValue: ViewRegistrar(limit: value))
self.content = content
}
public var body: some View {
@IanKeen
IanKeen / Example.swift
Last active March 24, 2026 10:05
ObservableObjectContainer: Consolidate nested/child ObservableObjects into a single publisher, useful for 'parent' ObservableObjects
// Setup
class Child: ObservableObject {
@Published var value = ""
}
class Parent: ObservableObjectContainer {
let single = Child()
let array = [Child(), Child()]
func updateSingle() {
@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 / View+Refreshable.swift
Created June 12, 2025 23:44
SwiftUI: Better `refreshable` - Prevent View redraws cancelling `refreshable` by making it stable
extension View {
public func _refreshable(_ action: @escaping () async -> Void) -> some View {
modifier(RefreshableTaskModifier(action: action))
}
}
private struct RefreshId {
var value: UUID
var continuation: CheckedContinuation<Void, Never>
}
@IanKeen
IanKeen / Banner.swift
Last active January 21, 2026 13:14
Persistent banner in SwiftUI : Supports top/bottom edge, swipe to dismiss + auto dismissal after time
public enum BannerEdge {
case top, bottom
}
public enum BannerAutoDismiss {
case after(TimeInterval)
case never
}
extension View {
public func banner<C: View>(
@IanKeen
IanKeen / Storage.swift
Last active December 6, 2025 18:28
PropertyWrapper: Storage to extend support for more types using `@AppStorage`
@propertyWrapper
struct Storage<T: AppStorageConvertible>: RawRepresentable {
var rawValue: String { wrappedValue.storedValue }
var wrappedValue: T
init?(rawValue: String) {
guard let value = T.init(rawValue) else { return nil }
self.wrappedValue = value
}
init(wrappedValue: T) {
@IanKeen
IanKeen / NeighborSequence.swift
Created September 2, 2020 23:41
Iterate a sequence with access to the previous/next elements if they exist
/// A collection that returns the current element as well as the previous and next elements when available
public struct NeighborSequence<Base: Sequence>: Sequence {
public typealias Element = (previous: Base.Element?, current: Base.Element, next: Base.Element?)
private let base: Base
fileprivate init(_ base: Base) {
self.base = base
}