Skip to content

Instantly share code, notes, and snippets.

@manmal
manmal / ScrollViewThatFits.swift
Last active March 1, 2024 16:08
Wrap a SwiftUI View in a ScrollView, expanding to full height/width & preventing bouncing when possible (iOS > = 16.4)
import SwiftUI
/// Wraps the content in a ScrollView that only bounces
/// if the content size exceeds the visible area;
/// and makes the content fill the ScrollView if desired.
/// Per default, the content fills the ScrollView only
/// vertically.
///
/// Usage:
///
@manmal
manmal / AsyncPipe.swift
Created November 24, 2022 14:55
Swift AsyncPipe (send values synchronously into an AsyncStream)
// MIT License
//
// Copyright (c) 2022 Manuel Maly
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
@manmal
manmal / AsyncPassthroughSubject.swift
Created July 17, 2022 09:44
AsyncPassthroughSubject - Swift Structured Concurrency
import Foundation
/// Provides a safe stream of `values`.
public struct AsyncPassthroughSubject<T> {
public let values: AsyncStream<T>
private let input: AsyncStream<T>.Continuation
private var isFinished = false
public init(
bufferingPolicy: AsyncStream<T>.Continuation.BufferingPolicy = .unbounded
@manmal
manmal / TaskAutoCancellation.swift
Last active July 27, 2022 20:52
Swift Structured Concurrency - Task Auto Cancellation
public extension Task {
/// Cancels this `Task` when the surrounding `Task` is cancelled.
/// This is necessary if `Task {}` and `Task.detached {}`
/// should be automatically cancelled - otherwise, such Tasks
/// just run until finished.
///
/// Usage:
///
/// await Task { await myAsyncFunc() }.autoCancel()
func autoCancel() async -> Void {
@manmal
manmal / AsyncSequenceExtensions.swift
Created July 6, 2022 16:57
AsyncSequence.eraseToAsyncStream()
import Foundation
// Props to @pteasima and @MichalKleinJr:
// https://twitter.com/pteasima/status/1544723987606929408?s=21&t=JL1oIuL87Ms_VPBQBZQ7Rg
public extension AsyncSequence {
func eraseToAsyncStream() -> AsyncStream<Element> {
return AsyncStream { continuation in
let task = Task {
do {
for try await value in self {
@manmal
manmal / content.txt
Created June 12, 2022 10:11
FB10198317 - Swift Charts: AxisValueLabel color does not change
When setting `foregroundStyle` on a `AxisValueLabel`, the rendered text color does not change.
Example Code:
```
Chart([(0,0), (1,1), (2, 2), (3, 3), (4, 4)], id: \.0) { point in
LineMark(x: .value("X", point.0), y: .value("Y", point.1))
}
.chartYAxis {
AxisMarks { _ in
@manmal
manmal / PDFToUIImage.swift
Last active February 8, 2022 20:29
PDF to UIImage (with capability to resize)
import Foundation
import UIKit
/// Renders the first page of the given PDF file to a `UIImage`. If
/// `maxLength` is given, then the resulting image is scaled to a
/// matching size.
///
/// Example: If `maxLength` is set to `100.0`, this might result in
/// the following dimensions (since aspect ratio is preserved):
///
@manmal
manmal / Reducer+OnChange.swift
Last active June 21, 2021 18:17
On-change handlers for Composable Architecture Reducers
// Original version from the authors of ComposableArchitecture here:
// https://github.com/pointfreeco/isowords/blob/fcff52ccf176f40db55951d5897def7cd9b879cf/Sources/TcaHelpers/OnChange.swift
//
// The following adds a method for filtering changes with a predicate.
// This is written using reactiveswift-composable-architecture, but can be adapted very quickly for Combine.
import ComposableArchitecture
import ReactiveSwift
public extension Reducer {
@manmal
manmal / AsyncObservableObject.swift
Last active June 11, 2021 15:32
Async ObservableObject
import SwiftUI
@MainActor
class PhotoStore: ObservableObject {
@Published private(set) var isSaving: Bool = false
// Made nonisolated because Playgrounds does not run on
// @MainActor. There's probably a cleaner way of doing this
nonisolated init() {}
@manmal
manmal / ActorReentrancyProblem.swift
Last active June 8, 2021 18:44
Potential reentrancy problem in Swift Actors
import Foundation
// Crashes when count is set to 683. Works fine if count < 683.
// Usage:
// func testMessagePassing() throws {
// let coordinator = Coordinator()
// let expectation = XCTestExpectation()
// detach {
// await coordinator.simulateMessengers()