Skip to content

Instantly share code, notes, and snippets.

@moyerr
moyerr / StreamChanges.swift
Created February 5, 2025 17:24
A SwiftUI ViewModifier for receiving state changes in an AsyncStream
extension View {
func streamChanges<Value: Equatable & Sendable>(
of value: Value,
provideStream: @escaping @Sendable (AsyncStream<Value>) async -> Void
) -> some View {
modifier(ChangeStream(value: value, provideStream: provideStream))
}
}
private struct ChangeStream<Value: Equatable & Sendable>: ViewModifier {
@moyerr
moyerr / SelfSizingSheetPresentation.swift
Created October 30, 2024 14:42
A modifier that provides automatic sizing for sheets in SwiftUI (iOS 16+)
import SwiftUI
struct SelfSizingSheetPresentation: ViewModifier {
private enum BoundsPreference: PreferenceKey {
static let defaultValue: Anchor<CGRect>? = nil
static func reduce(value: inout Value, nextValue: () -> Value) {
value = nextValue()
}
}
@moyerr
moyerr / AsyncIntervalSequence.swift
Created October 3, 2024 19:10
An AsyncSequence that iterates at most once every `interval`
/// An AsyncSequence that iterates at most once every `interval`
public struct AsyncIntervalSequence<Base: AsyncSequence, C: Clock> {
public let base: Base
public let interval: C.Instant.Duration
public let clock: C
public init(_ base: Base, interval: C.Instant.Duration, clock: C) {
self.base = base
self.interval = interval
self.clock = clock
@moyerr
moyerr / AsyncTimeoutSequence.swift
Created October 3, 2024 19:09
An AsyncSequence that will terminate with a `Timeout` error if iteration time exceeds the provided `timeout`.
/// An AsyncSequence that will terminate with a `Timeout` error if
/// iteration time exceeds the provided `timeout`.
struct AsyncTimeoutSequence<Base: AsyncSequence, C: Clock> {
struct Timeout: Error {}
let base: Base
let timeout: C.Instant.Duration
let clock: C
init(_ base: Base, timeout: C.Instant.Duration, clock: C) {
@moyerr
moyerr / RecursiveModifier.swift
Created November 7, 2023 18:01
Apply a modifier to a view repeatedly with a recursive modifier
import SwiftUI
struct RecursiveModifier<Data: Collection, Transformed: View>: ViewModifier {
let data: Data
let transform: (Data.Element, AnyView) -> Transformed
func body(content: Content) -> some View {
var subsequence = data[...]
if let first = subsequence.popFirst() {
@moyerr
moyerr / SwiftUINavigation.swift
Created July 7, 2023 17:17
A demonstration of navigation in SwiftUI using NavigationStack and Environment actions
import SwiftUI
// MARK: Navigation
enum Screen: String, Hashable, CaseIterable, CustomStringConvertible {
case first, second, third
var description: String {
rawValue.capitalized
}
struct AsyncWrappedSequence<Base: Sequence>: AsyncSequence {
typealias Element = Base.Element
struct AsyncIterator<BaseIterator>: AsyncIteratorProtocol where BaseIterator == Base.Iterator {
var base: BaseIterator
mutating func next() async -> BaseIterator.Element? {
base.next()
}
}
@moyerr
moyerr / AnyAsyncSequence.swift
Created May 17, 2023 17:54
A type-erased AsyncSequence
struct AnyAsyncSequence<Element>: AsyncSequence {
struct AnyAsyncIterator: AsyncIteratorProtocol {
private let _next: () async throws -> Element?
init<Base: AsyncSequence>(_ base: Base) where Base.Element == Element {
var baseIterator = base.makeAsyncIterator()
self._next = { try await baseIterator.next() }
}
func next() async throws -> Element? {
@moyerr
moyerr / AsyncButton.swift
Last active January 26, 2023 22:16
A UIButton subclass that delivers its press events via an AsyncStream
import UIKit
class AsyncButton: UIButton {
private var continuation: AsyncStream<Void>.Continuation?
private(set) lazy var presses: AsyncStream<Void> = AsyncStream { continuation in
configureContinuation(continuation)
}
deinit { continuation?.finish() }
@moyerr
moyerr / InterleavedSequence.swift
Created September 17, 2022 14:04
An implementation of a sequence produced by interleaving two other sequences
struct InterleavedSequence<First: Sequence, Second: Sequence>: Sequence where First.Element == Second.Element {
let first: First
let second: Second
init(first: First, second: Second) {
self.first = first
self.second = second
}
func makeIterator() -> Iterator {