Skip to content

Instantly share code, notes, and snippets.

Avatar
🏂

Ian Keen IanKeen

🏂
View GitHub Profile
@IanKeen
IanKeen / SizeClass.swift
Created Jul 2, 2022
PropertyWrapper: SwiftUI SizeClass helper
View SizeClass.swift
//v1: just find out if sizeclass is regular
@propertyWrapper
struct SizeClass: DynamicProperty {
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Environment(\.verticalSizeClass) var verticalSizeClass
var wrappedValue: Bool {
horizontalSizeClass == .regular && verticalSizeClass == .regular
}
}
View AnyEquatable.swift
public struct AnyEquatable: Equatable {
public let base: Any
private let isEqual: (_ other: Any) -> Bool
public init<T: Equatable>(_ value: T) {
self.base = value
self.isEqual = { other in
guard let other = other as? T else { return false }
return other == value
}
@IanKeen
IanKeen / RetryWhen.swift
Last active Jun 1, 2022
Combine: RetryWhen
View RetryWhen.swift
import Combine
import Foundation
public extension Publisher {
func retryWhen(max: Int = .max, delay: DispatchQueue.SchedulerTimeType.Stride = 0, _ predicate: @escaping Publishers.RetryWhen<Self>.Predicate) -> Publishers.RetryWhen<Self> {
.init(upstream: self, max: max, delay: delay, predicate: predicate)
}
}
extension Publishers {
@IanKeen
IanKeen / UserDefaultsKey.swift
Last active May 2, 2022
Simple type safe wrapper around UserDefaults
View UserDefaultsKey.swift
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)
View AnyCodable.swift
public struct AnyCodable: Codable {
public var base: Any
public init(_ base: Any) {
self.base = base
}
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
guard !container.decodeNil() else {
@IanKeen
IanKeen / Namespace.swift
Created Dec 18, 2021
Namespace and Implicit member chains
View Namespace.swift
// 1. Create a generic namespace we can ue to 'hang' values off
public struct Namespace<Base> { }
// 2. Add a namespace to a type(s) with the desired name
extension Color {
public static var theme: Namespace<Self> { .init() }
}
extension Font {
public static var theme: Namespace<Self> { .init() }
}
@IanKeen
IanKeen / Example.swift
Last active Jun 2, 2022
ObservableObjectContainer: Consolidate nested/child ObservableObjects into a single publisher, useful for 'parent' ObservableObjects
View Example.swift
// Setup
class Child: ObservableObject {
@Published var value = ""
}
class Parent: ObservableObjectContainer {
let child = Child()
func updateChild() {
child.value = "hello world"
@IanKeen
IanKeen / .swift
Last active Oct 14, 2021
SwiftUI: quick and dirty nested ForEach debugger
View .swift
import SwiftUI
struct Location: Equatable {
var file: String
var line: UInt
}
private struct ForEachKey: EnvironmentKey {
static var defaultValue: [Location] = []
}
private extension EnvironmentValues {
@IanKeen
IanKeen / TopLevelDecoder+Nested.swift
Created Sep 18, 2021
Decode an object nested under a key
View TopLevelDecoder+Nested.swift
extension TopLevelDecoder {
func decode<T: Decodable>(_ type: T.Type, from input: Input, under: String) throws -> T {
let decoder = try decode(_Decoder.self, from: input).decoder
let container = try decoder.container(keyedBy: AnyCodingKey.self)
return try container.decode(T.self, forKey: .init(under))
}
}
private struct _Decoder: Decodable {
var decoder: Decoder
@IanKeen
IanKeen / Require.swift
Last active Sep 11, 2021
SwiftUI: Conditional views from optional bindings with required constraints
View Require.swift
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 {