jihoon.me Blog
website·Indexed 31 days ago
https://jihoon.meA personal blog by a junior iOS developer featuring technical posts on Swift, SwiftUI, and Tuist. Content includes guides on Swift Concurrency, Actors, Universal Frameworks, and the creation of TuistUI and Swift Layout. It also documents experiences with Publish for static site generation and retrospectives from LetSwift 2023 and IGA presentations.
What's inside jihoon.me
- Publish is a static site generator created by John Sundell. It is built using Swift and leverages the Ink Markdown parser and Plot (a DSL for writing HTML, XML, and RSS in Swift).
Overview of Swift Layout library
Swift Layout is a UIKit-based library that implements a SwiftUI-style Domain Specific Language (DSL) for Manual Layout. Unlike Auto Layout, which uses a Constraint Resolver (CPU-intensive), Swift Layout calculates frames mathematically and sequentially, providing the performance of Manual Layout with the developer productivity of SwiftUI.Overview of Swift Concurrency
Introduced in Swift 5.5, Swift Concurrency is a powerful toolset designed to solve common asynchronous programming problems, such as 'completion handler hell' and the complexity of managing asynchronous event streams in state-based architectures. UnlikeDispatchQueue, which is an executor, Swift Concurrency provides a comprehensive concurrency model focusing on structured concurrency, a cooperative thread pool, and compile-time data race prevention.Overview of the Swift Programming Language
Swift is a programming language developed by Apple for creating applications across iOS, macOS, watchOS, and tvOS. It is designed to be intuitive, easy to learn, and serves as a modern replacement for languages like C, C++, and Objective-C.Overview of Scade cross-platform framework
Scade is a cross-platform development framework that enables the simultaneous development of iOS and Android applications using the Swift programming language. It works by compiling Swift code into native binaries for both iOS and Android. As of the documented version, it supports Swift 5.4.DaySquare iOS App Overview and Features
DaySquare is an iOS and iPadOS application designed for daily schedule management. Key technical features include:
- Modular Architecture: Designed for high scalability.
- Timeline View: Allows users to view their daily schedule at a glance.
- Alarm Integration: Uses AlamKit for adding and modifying alarms.
- Local Notifications: Sends local push notifications when a scheduled event begins.
- Data Synchronization: Uses Supabase for remote data fetching with a local fallback mechanism for offline access.
Understand why MVVM may be redundant in SwiftUI
In SwiftUI, the View is designed as a declarative UI that inherently includes data binding capabilities. Because SwiftUI can reactively reflect model changes directly in the View, the primary purpose of a ViewModel—to bind state to the View for reactive updates—is already built into the framework. Adding a separate ViewModel layer can increase complexity and introduce bidirectional data flow, which contradicts the unidirectional data flow preferred in declarative UI environments (similar to React, Vue, and Flutter).import SwiftUI struct Content: View { // The View directly holds/observes the model, acting as its own ViewModel @State var model = Themes.listModel var body: some View { List(model.items, action: model.selectItem) { item in Image(item.image) VStack(alignment: .leading) { Text(item.title) Text(item.subtitle) .color(.gray) } } } }Alternative architecture patterns for SwiftUI
When moving away from MVVM in SwiftUI to maintain a separation of business logic and UI logic while preserving unidirectional data flow, consider the following architectural approaches:
- MVI (Model-View-Intent): An approach where the state is driven by intents, which is often recommended for declarative UIs.
- Flux/Store/Provider Patterns: Using a centralized Store to manage state and distribute it to views, ensuring a predictable, one-way data flow.
Prevent data races using Swift Actors
Anactoris a reference type introduced in Swift Concurrency to prevent data races at compile time. Unlike classes, actors ensure that only one task can access their mutable state at any given time, removing the need for manual synchronization usingDispatchQueue,NSLock, orSemaphore.Implement dynamic Section page routing
To handle different section pages (e.g., Blog vs. About), create aSectionPagecomponent that switches the rendered content based on thesection.path.string. This allows a singlemakeSectionHTMLfactory method to route to different page components.struct SectionPage: Component { var section: Publish.Section<Example> var context: PublishingContext<Example> var body: Component { switch section.path.string { case Example.SectionID.blog.rawValue: return IndexPage(context: context) case Example.SectionID.about.rawValue: return AboutPage(context: context) default: return Div() } } } func makeSectionHTML(for section: Publish.Section<Example>, context: Publish.PublishingContext<Example>) throws -> HTML { HTML( .lang(context.site.language), .head(for: section, on: context.site), .body { SectionPage(section: section, context: context) } ) }Understand SwiftUI's declarative syntax
SwiftUI uses a declarative syntax to define user interfaces. Instead of manually managing view hierarchies and constraints (as in UIKit), developers declare the components to be included, specify the layout manager (e.g., VStack, HStack, Form, List), and apply modifiers to set properties. SwiftUI automatically handles the complex details of layout positioning, constraints, and rendering.import SwiftUI struct ContentView: View { var body: some View { VStack { Text("Hello, world!") .frame(maxWidth: .infinity, maxHeight: .infinity) .foregroundColor(.white) } .padding() .background(.black) } }Determine when to use Actors vs Atomics
Actors are recommended for managing shared state in caches, stores, repositories, analytics, logging, ViewModels, and domain services.
Avoid actors in the following scenarios:
- Hot paths called hundreds of thousands of times per second.
- Very short atomic operations.
- Tight loops or numerical computation-heavy code.
In these high-performance cases, use
ManagedAtomic(Swift Atomics) or value types with task-local storage instead.