Snippets
Async Transferable for ShareLink
struct AsyncImageTransferable: Codable, Transferable {
let url: URL
func fetchAsImage() async -> Image {
let data = try? await URLSession.shared.data(from: url).0
guard let data, let uiimage = UIImage(data: data) else {
return Image(systemName: "photo")
}
return Image(uiImage: uiimage)
}
static var transferRepresentation: some TransferRepresentation {
ProxyRepresentation { media in
await media.fetchAsImage()
}
}
}
struct ShareView: View {
let imageURL: URL
var body: some View {
let transferable = AsyncImageTransferable(url: imageURL)
ShareLink(item: transferable, preview: .init("Share this image", image: transferable))
}
}
Access AppDelegate from SwiftUI App
@main
struct IceCubesApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegatern
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool
{
print("Application did finish lauching")
}
}
Programmatic navigation with NavigationStack
public enum RouterDestination: Hashable {
case accountDetail(id: String)
}
@MainActor
extension View {
func withAppRouter() -> some View {
navigationDestination(for: RouterDestination.self) { destination in
switch destination {
case let .accountDetail(id):
AccountDetailView(accountId: id)
}
}
}
}
@MainActor
public class RouterPath: ObservableObject {
@Published public var path: [RouterDestination] = []
public func navigate(to: RouterDestination) {
path.append(to)
}
}
struct NotificationsTab: View {
@StateObject private var routerPath = RouterPath()
var body: some View {
NavigationStack(path: $routerPath.path) {
Button("Navigate to account") {
routerPath.navigate(to: .accountDetail(id: accountId))
}
.withAppRouter()
}
}
}
Sheet with visual effect / blurred background and corner radius
public struct AppAccountsSelectorView: View {
@State private var isPresented: Bool = false
public var body: some View {
Button {
isPresented.toggle()
} label: {
Text("Present sheet")
}
.sheet(isPresented: $isPresented) {
accountsView
.presentationDetents([.height(preferredHeight), .large])
.presentationBackground(.thinMaterial)
.presentationCornerRadius(16)
}
}
}
Save array of Codable in @AppStorage
extension Array: RawRepresentable where Element: Codable {
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode([Element].self, from: data)
else {
return nil
}
self = result
}
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let result = String(data: data, encoding: .utf8)
else {
return "[]"
}
return result
}
}
Minimal SwiftUI + SwiftData app
@Model
final class Thread {
@Attribute(.unique) var id: UUID
var createdOn: Date
var content: String
var author: User
var isLiked: Bool = false
init(content: String, author: User) {
self.id = UUID()
self.createdOn = Date()
self.content = content
self.author = author
}
}
@Model
final class User {
@Attribute(.unique) var id: UUID
var username: String
init(username: String) {
self.id = UUID()
self.username = username
}
}
Creating and using custom Environment values in SwiftUI
public extension EnvironmentValues {
var isSecondaryColumn: Bool {
get { self[SecondaryColumnKey.self] }
set { self[SecondaryColumnKey.self] = newValue }
}
}
public struct NotificationsTab: View {
public var body: some View {
NotificationsListView()
.environment(\.isSecondaryColumn, true)
}
}
public struct NotificationsListView: View {
@Environment(\.isSecondaryColumn) private var isSecondaryColumn: Bool
public var body: some View {
if isSecondaryColumn {
Text("I'm secondary column")
} else {
Text("I'm not secondary column")
}
}
}
2023 © Thomas Ricouard.