Skip to content

Instantly share code, notes, and snippets.

@ole
ole / NSHostingViewGenerics.swift
Created May 5, 2023 18:21
Avoiding AnyView when using NSHostingView with arbitrary content. Finding a way to specify the generic parameter.
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
FrameworkView1 {
Text("FrameworkView1")
}
.border(.red)
@ole
ole / UserDefaultsAsyncSequence.swift
Last active December 9, 2024 16:32
UserDefaults KVO observation with AsyncSequence/AsyncStream
// UserDefaults KVO observation with AsyncSequence/AsyncStream
// Ole Begemann, 2023-04
// Updated for Swift 6, 2024-11
// https://gist.github.com/ole/fc5c1f4c763d28d9ba70940512e81916
import Foundation
// This is ugly, but UserDefaults is documented to be thread-safe, so this
// should be OK.
extension UserDefaults: @retroactive @unchecked Sendable {}
@ole
ole / RelativeSizeLayout.swift
Last active December 30, 2024 16:48
A SwiftUI layout and modifier for working with relative sizes ("50 % of your container"). https://oleb.net/2023/swiftui-relative-size/
import SwiftUI
extension View {
/// Proposes a percentage of its received proposed size to `self`.
///
/// This modifier multiplies the proposed size it receives from its parent
/// with the given factors for width and height.
///
/// If the parent proposes `nil` or `.infinity` to us in any dimension,
/// we’ll forward these values to our child view unchanged.
@ole
ole / TaskGroupFireAndForget.swift
Last active March 22, 2023 16:27
Swift TaskGroup swallows errors if you use it for fire-and-forget tasks (i.e. you never await the child tasks)
struct MyError: Error {}
func fireAndForget() async {
await withThrowingTaskGroup(of: Void.self) { group in
group.addTask {
print("child task start")
print("child task throws")
throw MyError()
}
// Notice that we're not awaiting the child task.
@ole
ole / set-photos-keyboard-shortcuts.sh
Last active May 4, 2024 02:10
Assign a keyboard shortcut to the Export Unmodified Originals menu command in Photos.app on macOS
#!/bin/bash
# Assigns a keyboard shortcut to the Export Unmodified Originals
# menu command in Photos.app on macOS.
# @ = Command
# ^ = Control
# ~ = Option
# $ = Shift
shortcut='@~^e'
@ole
ole / FinderFileColors.swift
Created February 2, 2023 11:43
Assign colors (as shown in the macOS Finder) to files
import Foundation
enum FinderColor: Int {
case noColor = 0
case grey = 1
case green = 2
case purple = 3
case blue = 4
case yellow = 5
case red = 6
@ole
ole / CodableContainerVsEncoder.swift
Created January 1, 2023 15:43
Illustrating the differences between encoding through a encoding container (recommended) vs. calling encode(to:) directly on the encoder (generally not recommended).
import Foundation
struct ContainerEncoded: Encodable {
var date: Date = .now
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(date)
}
}
@ole
ole / NoLargerThanLayout.swift
Last active December 16, 2022 06:47
SwiftUI: Show a view with its ideal size, but no larger than a given maximum size. The view must be flexible, otherwise it may stretch out of the wrapping frame. Two variants: as a custom Layout (iOS 16+), or with manual measuring using GeometryReader.
import SwiftUI
extension View {
func noLargerThan(_ maxSize: CGSize) -> some View {
NoLargerThanLayout(maxSize: maxSize) {
self
}
}
}
@ole
ole / clipped-hit-testing.swift
Last active January 9, 2025 10:50
SwiftUI: .clipped() doesn’t limit hit testing to the visible area. This is the sample code for https://oleb.net/2022/clipped-hit-testing/
import SwiftUI
struct ContentView: View {
@State private var buttonTapCount: Int = 0
@State private var rectTapCount: Int = 0
@State private var isClippingDisabled: Bool = false
@State private var activateContentShape: Bool = false
var body: some View {
VStack(spacing: 40) {
@ole
ole / ListScrollPosition.swift
Created November 17, 2022 10:40
SwiftUI: control List scroll position on element insert
import SwiftUI
struct Item: Identifiable {
var id: UUID = .init()
var value: Int
}
let sampleItems: [Item] = (1...99).map { Item.init(value: $0) }
struct ContentView: View {