Skip to content

Instantly share code, notes, and snippets.

@yannxou
yannxou / ProcessInfo+SwiftUIPreview.swift
Created April 5, 2024 11:07
Swift: Detect code running in SwiftUI preview
extension ProcessInfo {
var isSwiftUIPreview: Bool {
environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
}
// or:
static func isOnPreview() -> Bool {
return processInfo.processName == "XCPreviewAgent"
@yannxou
yannxou / OneShotSubscription.swift
Last active April 2, 2024 09:36
Combine: One-shot subscriptions
// Credit: https://www.apeth.com/UnderstandingCombine/subscribers/subscribersoneshot.html
var cancellable: AnyCancellable?
cancellable = pub.sink(receiveCompletion: {_ in
cancellable?.cancel()
}) { image in
self.imageView.image = image
}
// Or just subscribe to the Subscribers.Sink:
@yannxou
yannxou / ScrollToModifier.swift
Created September 28, 2023 12:58
SwiftUI: ScrollToModifier
import SwiftUI
public struct ScrollToModifier<T: Hashable>: ViewModifier {
@Binding var id: T?
public func body(content: Content) -> some View {
ScrollViewReader { proxy in
content
.onChange(of: id) { newValue in
if let id {
scrollTo(id: id, using: proxy)
@yannxou
yannxou / ActorReentrancy.swift
Last active September 15, 2023 07:11
Swift: Handling actor reentrancy correctly
// Code from: https://alexdremov.me/swift-actors-common-problems-and-tips/
import Foundation
actor ActivitiesStorage {
var cache = [UUID: Task<Data?, Never>]()
func retrieveHeavyData(for id: UUID) async -> Data? {
if let task = cache[id] {
return await task.value
@yannxou
yannxou / onTapGestureAsync.swift
Created July 26, 2023 10:40
SwiftUI onTapGesture modifier async
extension View {
func onTapGesture(perform action: () async -> Void) -> some View {
self.onTapGesture {
Task { await action() }
}
}
}
@yannxou
yannxou / forcaselet.swift
Last active July 13, 2023 12:08
Swift: For case let example
import Foundation
enum State {
case idle
case running(speed: Double)
case paused(duration: TimeInterval)
case stopped(reason: String)
}
let states: [State] = [.idle, .paused(duration: 2), .running(speed: 10), .running(speed: 2)]
@yannxou
yannxou / ForegroundTextColor.swift
Created December 23, 2020 09:55
Foreground text color based on background color #SwiftUI
// Taken from Apple's App Dev Training: https://developer.apple.com/tutorials/app-dev-training/
/// This color is either black or white, whichever is more accessible when viewed against the scrum color.
var accessibleFontColor: Color {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
UIColor(self).getRed(&red, green: &green, blue: &blue, alpha: nil)
return isLightColor(red: red, green: green, blue: blue) ? .black : .white
}
@yannxou
yannxou / View+BindingSync.swift
Last active February 23, 2023 16:50
SwiftUI: Synchronize bindings
import SwiftUI
extension View {
/// Synchronizes the bindings so changes in any of them are propagated to the other.
///
/// The following example shows how to synchronize a Published property in a view model with a Binding used for presenting a sheet:
/// ```
/// class ViewModel: ObservableObject {
/// @Published var isPresented = false
@yannxou
yannxou / FileComponents.swift
Created February 22, 2023 15:30
Swift: Split filename and extension
private func fileComponents(_ fileName: String) -> (name: String, extension: String) {
let fileExtension = URL(fileURLWithPath: fileName).pathExtension
let fileNameOnly = fileExtension.isEmpty ? fileName : String(fileName.dropLast(fileExtension.count + 1))
return (fileNameOnly, fileExtension)
}
@yannxou
yannxou / SwiftUI Badge
Created April 22, 2020 15:13
SwiftUI Badge #SwiftUI
// code from the book “Thinking in SwiftUI” by Chris Eidhof
extension View {
func badge(count: Int) -> some View {
overlay(
ZStack {
if count != 0 {
Circle()
.fill(Color.red)
Text("\(count)")