<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Priyank Gandhi on Medium]]></title>
        <description><![CDATA[Stories by Priyank Gandhi on Medium]]></description>
        <link>https://medium.com/@iosdev.priyank?source=rss-4cf4c83bdd7e------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*34LfbmvfFC10tCGS6CvtUw.png</url>
            <title>Stories by Priyank Gandhi on Medium</title>
            <link>https://medium.com/@iosdev.priyank?source=rss-4cf4c83bdd7e------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 29 May 2026 17:51:40 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@iosdev.priyank/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Meet Singleton: The Friend Who Shows Up Everywhere]]></title>
            <link>https://medium.com/@iosdev.priyank/meet-singleton-the-friend-who-shows-up-everywhere-b0fc4938e767?source=rss-4cf4c83bdd7e------2</link>
            <guid isPermaLink="false">https://medium.com/p/b0fc4938e767</guid>
            <category><![CDATA[clean-architecture]]></category>
            <category><![CDATA[concurrency]]></category>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[swiftui]]></category>
            <dc:creator><![CDATA[Priyank Gandhi]]></dc:creator>
            <pubDate>Fri, 12 Dec 2025 11:58:52 GMT</pubDate>
            <atom:updated>2025-12-12T11:58:52.157Z</atom:updated>
            <content:encoded><![CDATA[<p>Singletons are easy to write, hard to maintain, and almost impossible to test… unless you finally learn how to use them the right way.</p><h4><strong>Why You Should Read This:</strong></h4><p>This is <strong>not</strong> another “boring Singleton” article. This is the real-world guide to Singletons that production codebases actually need.</p><p><strong><em>This is:</em></strong><br><strong>The real mistakes</strong> you are making right now in production code<strong><br>Why your tests fail</strong> or require elaborate mocking gymnastics<br><strong>The @MainActor confusion</strong> that’s causing crashes you can’t reproduce<br><strong>Thread safety pitfalls</strong> that only show up under load<br><strong>The architecture patterns</strong> that distinguish senior developers from everyone else</p><p><strong><em>By the end, </em></strong>you will have a <strong>battle-tested, testable architecture</strong> that scales with your team and your app.</p><h3><strong>The Monster Singleton — A God Object</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LCo_2wZkgHn5kV8QaGeCmw.png" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9da98bcef766deced46a05cbaabb0495/href">https://medium.com/media/9da98bcef766deced46a05cbaabb0495/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iVuscaaxW5dAVBBG1oIpyA.png" /></figure><p><strong>The Symptoms You are Already Experiencing:</strong><br>- <strong>You dread opening a file: </strong>It has 1000+ lines of code.<br>- <strong>Everyone touches it:</strong> Merge conflicts every sprint<br><strong>- Nothing can be tested in isolation: </strong>Your test suite is a mess. <br>- <strong>Changes cascade unpredictably: </strong>Fix one method, break five screens.<br>- <strong>Thread safety is a prayer</strong> — Sometimes it crashes, sometimes it doesn’t</p><p>What started as convenience evolved into a <strong>global state that became a monster or God Object.</strong></p><blockquote><strong>Why This Singleton Is Untestable?</strong></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*t5bUxue5KKz7eGPCECEiQQ.png" /></figure><p><strong>This class violates every principle of good design:<br>1. It mixes responsibilities</strong> — UI, networking, business logic, and caching all jammed together.<br><strong>2. Exposed Mutable State — </strong>Anyone, anywhere can modify anything<br><strong>3. Tight Coupling — </strong>Every feature directly depends on this global object<br><strong>4. No Abstraction — </strong>Can’t swap implementations, can’t test parts independently<br><strong>5. Thread Chaos — </strong>No isolation, no safety guarantees<br>6. <strong>Memory Hoarding</strong> — Global state means global memory consumption</p><h3>The Core Insight That Changes Everything</h3><p>We don’t fix monsters by fighting them.<br>We fix them by isolating them.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1020/1*tKQCiqoAIuG0fDnnriMONA.png" /></figure><p><strong>Tumb Rule: </strong><em>Never depend on </em><em>.shared directly inside business logic. </em>Depend on the protocols that the Singleton implements.</p><blockquote><strong>This single change transforms everything.</strong></blockquote><p><strong>Before: Tight Coupling Hell</strong></p><pre>class CartViewModel {<br>    func loadCart() {<br>        let items = AppManager.shared.cartItems  // Locked to global state<br>        // Can&#39;t test without AppManager<br>        // Can&#39;t swap implementations<br>        // Can&#39;t run tests in parallel<br>    }<br>}</pre><p><strong>After: Protocol-Based Isolation</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ENh93EZuHQDAyeMW-FML6A.png" /></figure><pre>// Define what you need, not how it&#39;s implemented<br>protocol CartReadable {<br>    func items() async -&gt; [CartItem]<br>}<br><br>protocol CartWritable {<br>    func add(_ item: CartItem) async<br>}<br><br>// Singleton implements the protocols<br>actor CartStore: CartReadable, CartWritable {<br>    static let shared = CartStore()<br>    private var cart: [CartItem] = []<br><br>    func items() async -&gt; [CartItem] { cart }<br>    func add(_ item: CartItem) async { cart.append(item) }<br>}</pre><p><strong>Why this matters:</strong></p><ul><li>Business logic depends on <strong>capabilities</strong>, not concrete types</li><li>Tests can inject <strong>fake implementations</strong> without touching production code</li><li>You can <strong>swap implementations</strong> without changing the calling code</li><li>Dependencies are <strong>explicit and visible</strong> in initialisers</li></ul><h3>Dependency Injection — The Pattern That Makes Testing Possible</h3><p><strong>The Problem:</strong> Hidden Global Dependencies<br>When you write AppManager.shared.somethingYou&#39;ve created an <strong>invisible dependency</strong>. The function signature doesn&#39;t show what it needs. Tests can&#39;t control it.</p><p><strong>The Solution:</strong></p><pre>final class CartViewModel {<br>    private let store: CartReadable &amp; CartWritable<br><br>    // Default to production, but allow injection for tests<br>    init(store: (CartReadable &amp; CartWritable)? = = nil) {<br>        self.store = store ?? CartStore.shared<br>    }<br><br>    func loadCart() async -&gt; [CartItem] {<br>        await store.items()<br>    }<br>}</pre><p><strong>Why the </strong><strong>? = nil Pattern in Swift 6?</strong></p><p>This avoids the “Main actor-isolated property accessed from nonisolated context” error:</p><pre>// Old pattern - causes Swift 6 errors<br>init(store: CartReadable &amp; CartWritable = CartStore.shared) {<br>    // Default evaluated at call site = requires await everywhere!<br>}<br><br>// New pattern - Swift 6 compliant<br>init(store: (CartReadable &amp; CartWritable)? = nil) {<br>    self.store = store ?? CartStore.shared<br>    // Default evaluated inside init = no await needed!<br>}</pre><p><strong>What changed:</strong></p><ul><li>The dependency is <strong>visible in the initialiser</strong></li><li>Production code uses the default: CartViewModel() — no changes needed</li><li>Test code injects a mock: CartViewModel(store: mockStore) — <strong>no await required!</strong></li><li>Swift 6 concurrency is fully supported</li></ul><p><strong>Your Test</strong></p><pre>// Mock implementation<br>final class MockCartStore: CartReadable, CartWritable {<br>    var data = [CartItem]()<br>    <br>    func items() async -&gt; [CartItem] { data }<br>    func add(_ item: CartItem) async { data.append(item) }<br>}<br><br><br>func test_loading_cart() async {<br>    // Create a controlled fake<br>    let mock = MockCartStore()<br>    mock.data = [CartItem(id: 1), CartItem(id: 2)]<br><br>    // Inject it<br>    let vm = CartViewModel(store: mock)<br>    <br>    // Test in complete isolation<br>    let result = await vm.loadCart()<br><br>    XCTAssertEqual(result.count, 2)<br>}</pre><p><strong>Results:<br></strong>No global state pollution<br>No .shared calls<br>No side effects between tests<br>Yes, Fast, reliable, parallel-safe tests</p><h3>Thread Safety — Understanding Sendable and When Actors Matter</h3><p><strong>The Confusion: </strong>When Should a Singleton Be Sendable?<br><strong>Short answer:</strong> Rarely, and only in specific cases.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pVC1ZTvfu-2qVivDtymrSA.png" /></figure><p>Let’s break down the scenarios.</p><p><strong>Mistake 1:</strong> <em>Forcing Sendable on Class Singletons</em></p><pre>final class Logger: Sendable {   // Compiler error incoming<br>    static let shared = Logger()<br>    private init() {}<br>    <br>    var logs: [String] = []  // Mutable state = not Sendable<br>}</pre><p><strong>Error:</strong> &quot;Class &#39;Logger&#39; does not conform to Sendable&quot;</p><p><strong>Why it fails:</strong></p><p>Classes with mutable state are <strong>inherently unsafe</strong> to share across threads. No amount of annotation fixes this. The compiler is protecting you from data races.</p><p><strong>The mistake:</strong> Trying to paper over thread safety with Sendable conformance.</p><p><strong>Solution 1:</strong> Use an Actor for Mutable Shared State</p><pre>actor Logger {<br>    static let shared = Logger()<br>    <br>    private var logs: [String] = []<br>    <br>    func log(_ message: String) {<br>        logs.append(message)  // Safe: actor provides isolation<br>    }<br>}</pre><p><strong>Why this works:</strong></p><ul><li>Actors provide <strong>automatic isolation</strong> — only one task accesses the state at a time</li><li>Actors are <strong>automatically Sendable</strong> — safe to pass between concurrency domains</li><li>The compiler <strong>enforces safe access patterns</strong> at compile time</li></ul><p><strong>Solution 2:</strong> Immutable Singleton Structs</p><pre>struct AppConfig: Sendable {<br>    let apiBaseURL: String<br>    let timeout: TimeInterval<br>    <br>    static let shared = AppConfig(<br>        apiBaseURL: &quot;https://api.example.com&quot;,<br>        timeout: 30<br>    )<br>}</pre><p><strong>Why this works:</strong></p><p>Immutable data is <strong>inherently thread-safe</strong>. No synchronisation needed because nothing changes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*k0ckTRhyzqtsNtjCWgAPcA.png" /></figure><h3>The @MainActor Trap — When UI Safety Becomes a Performance Prison</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Sz9XgRZZ0i06RyzSObeSYA.png" /></figure><h4>What @MainActor Actually Does</h4><p>It <strong>forces all access</strong> to happen on the main thread. This is:</p><ul><li>Perfect for <strong>UI states</strong> that UIKit/SwiftUI require on the main thread</li><li>Disastrous for <strong>networking, caching, or heavy computation</strong></li></ul><p><strong>The Mistake:</strong> @MainActor on Everything</p><pre>@MainActor<br>final class ImageCache {<br>    static let shared = ImageCache()<br>    private var cache = [String: UIImage]()  // Blocks main thread<br>    <br>    func store(_ image: UIImage, for url: String) {<br>        // This now runs on main thread<br>        // Blocks your UI during large operations<br>        cache[url] = image<br>    }<br>}</pre><p><strong>What goes wrong:</strong></p><ul><li>Image processing <strong>blocks UI updates</strong></li><li>Cache operations <strong>freeze scrolling</strong></li><li>Memory warnings <strong>trigger on the main thread</strong>, blocking user interaction</li><li>Your app feels <strong>sluggish under load</strong></li></ul><p><strong>The Fix:</strong> Use @MainActor Only for Actual UI State.</p><pre>// CORRECT: UI state on main actor<br>@MainActor<br>final class UIState: ObservableObject {<br>    static let shared = UIState()<br>    @Published var isLoggedIn = false<br>    @Published var selectedTab: Tab = .home<br>}<br><br>// CORRECT: UI state on main actor for iOS 17+<br>@MainActor<br>@Observable<br>final class UIState {<br>    static let shared = UIState()<br><br>    var isLoggedIn = false<br>    var selectedTab: Tab = .home<br><br>    private init() {}<br>}<br><br>// CORRECT: Heavy work in isolated actor<br>actor ImageCache {<br>    static let shared = ImageCache()<br>    private var store = [String: Data]()  // Store Data, not UIImage<br>    <br>    func store(_ data: Data, for url: String) {<br>        store[url] = data<br>    }<br>}</pre><h4>The @MainActor Decision Guide</h4><p><strong>Use @MainActor for:</strong></p><ul><li>@Published properties in ObservableObject</li><li>UI state flags (login status, theme selection)</li><li>Navigation state</li><li>Anything directly bound to SwiftUI views</li></ul><p><strong>Never use @MainActor for:</strong></p><ul><li>Network operations</li><li>File I/O</li><li>Image processing</li><li>JSON parsing</li><li>Database operations</li></ul><h3>Real-World Refactor — Turning Chaos Into Clean Architecture</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CZsDT73PfyUWGkIWYkZjOA.png" /></figure><p><strong>The Starting Point:</strong> Your Current God-Singleton</p><pre>final class AppManager {<br>    static let shared = AppManager()<br>    <br>    var user: User?<br>    var cachedImages = [String: UIImage]()<br>    <br>    func fetchProducts() async -&gt; [Product] { /* networking */ }<br>    func calculateDiscount(cart: [Item]) -&gt; Double { /* business logic */ }<br>    func loadHomeUI() { /* UI coordination */ }<br>    func trackEvent(_ name: String) { /* analytics */ }<br>}</pre><p><strong>This singleton does everything. That’s the problem.<br>The Refactored Architecture: Separated Concerns</strong></p><ol><li><strong>UI State</strong> — Main Thread Safe</li></ol><pre>@MainActor<br>final class UIState: ObservableObject {<br>    static let shared = UIState()<br>    <br>    @Published var isLoggedIn = false<br>    @Published var currentUser: User?<br><br>    private init() {}<br>}<br><br>// For iOS 17+<br>@MainActor<br>@Observable<br>final class UIState {<br>    static let shared = UIState()<br><br>    var isLoggedIn = false<br>    var currentUser: User?<br><br>    private init() {}<br>}</pre><p><strong>Purpose:</strong> UI bindings only. Fast, main-thread-safe updates.</p><p><strong>2. Networking </strong>— Protocol-Based for Testing</p><pre>protocol ProductAPI {<br>    func fetchProducts() async throws -&gt; [Product]<br>}<br><br>struct RealProductAPI: ProductAPI {<br>    func fetchProducts() async throws -&gt; [Product] {<br>        // Real network call<br>        let url = URL(string: &quot;https://api.example.com/products&quot;)!<br>        let (data, _) = try await URLSession.shared.data(from: url)<br>        return try JSONDecoder().decode([Product].self, from: data)<br>    }<br>}<br><br>// Test mock<br>struct MockProductAPI: ProductAPI {<br>    var productsToReturn: [Product] = []<br>    <br>    func fetchProducts() async throws -&gt; [Product] {<br>        productsToReturn<br>    }<br>}</pre><p><strong>Purpose:</strong> Network operations. Mockable for tests.</p><p><strong>3. Business Logic</strong> — Pure, Testable Functions</p><pre>struct DiscountEngine {<br>    func calculate(cart: [Item]) -&gt; Double {<br>        let subtotal = cart.reduce(0) { $0 + $1.price }<br>        let discount = subtotal &gt; 100 ? subtotal * 0.1 : 0<br>        return subtotal - discount<br>    }<br>}</pre><p><strong>Purpose:</strong> Pure logic. No dependencies. Fast unit tests.</p><p><strong>4. Caching</strong> — Actor-Isolated, Thread-Safe</p><pre>actor ImageCache {<br>    static let shared = ImageCache()<br>    <br>    private var store = [String: Data]()<br>    private var maxBytes: Int = 50_000_000  // 50MB limit<br>    <br>    func store(_ data: Data, for url: String) {<br>        if currentSize() &gt; maxBytes {<br>            evictOldest()<br>        }<br>        store[url] = data<br>    }<br>    <br>    func retrieve(for url: String) -&gt; Data? {<br>        store[url]<br>    }<br>    <br>    private func currentSize() -&gt; Int {<br>        store.values.reduce(0) { $0 + $1.count }<br>    }<br>    <br>    private func evictOldest() {<br>        // Implement LRU or similar<br>    }<br>}</pre><p><strong>Purpose:</strong> Safe caching without blocking UI.</p><p><strong>5. Environment Coordinator</strong> — Thin Wiring Layer</p><pre>@MainActor<br>final class AppEnvironment {<br>    static let shared = AppEnvironment()<br><br>    let ui = UIState.shared<br>    let productAPI: ProductAPI<br>    let discountEngine = DiscountEngine()<br>    let cache = ImageCache.shared<br><br>    init(productAPI: ProductAPI = RealProductAPI()) {<br>        self.productAPI = productAPI<br>    }<br>}</pre><p><strong>Purpose:</strong> Wire dependencies together. No logic, just composition.</p><p><strong>What Changed:</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3d161cc01aa31b5daf191b8a8968c4f7/href">https://medium.com/media/3d161cc01aa31b5daf191b8a8968c4f7/href</a></iframe><h4><strong>Testing Every Layer</strong></h4><p><strong>Testing Business Logic</strong></p><pre>func test_discount_calculation() {<br>    let engine = DiscountEngine()<br>    let cart = [<br>        Item(price: 50),<br>        Item(price: 60)<br>    ]<br>    <br>    let result = engine.calculate(cart: cart)<br>    <br>    XCTAssertEqual(result, 99.0)  // 110 - 11 (10% discount)<br>}</pre><ul><li>No mocks. No setup. Pure function testing.</li></ul><p><strong>Testing ViewModels with Injected Dependencies</strong></p><pre>final class CartViewModel {<br>    private let cart: CartReadable<br>    private let discount: DiscountEngine<br><br>    init(cart: CartReadable = CartStore.shared, discount: DiscountEngine = DiscountEngine()) {<br>        self.cart = cart<br>        self.discount = discount<br>    }<br><br>    func total() async -&gt; Double {<br>        let items = await cart.items()<br>        return discount.calculate(cart: items.map { $0.item })<br>    }<br>}<br><br>// Test<br>func test_total_calculation() async {<br>    let mockCart = MockCartStore()<br>    mockCart.data = [<br>        CartItem(item: Item(price: 10)),<br>        CartItem(item: Item(price: 20))<br>    ]<br><br>    let vm = CartViewModel(cart: mockCart)<br>    let total = await vm.total()<br><br>    XCTAssertEqual(total, 30)<br>}</pre><p><strong>Testing Actor Singletons</strong></p><pre>func test_image_cache_storage() async {<br>    let cache = ImageCache()  // Create instance for test<br>    let testData = Data([0x1, 0x2, 0x3])<br>    <br>    await cache.store(testData, for: &quot;test-url&quot;)<br>    let retrieved = await cache.retrieve(for: &quot;test-url&quot;)<br>    <br>    XCTAssertEqual(retrieved, testData)<br>}</pre><ul><li>Isolated actors. No shared state between tests.</li></ul><p><strong>Testing UI State (Main Actor)</strong></p><pre>@MainActor<br>func test_login_state_change() async {<br>    let state = UIState()<br>    <br>    XCTAssertFalse(state.isLoggedIn)<br>    <br>    state.isLoggedIn = true<br>    <br>    XCTAssertTrue(state.isLoggedIn)<br>}</pre><ul><li>Main actor tests stay on the main thread.</li></ul><h4>Complete Example — Shopping App Architecture</h4><p><strong>Want to see this in action?</strong> Check out the complete working implementation on GitHub: <a href="https://github.com/iosdevpriyank/ShoppingApp"><strong>Swift-Singleton-Architecture-Example</strong></a>.<br>Clone it, run it, and see the patterns from this article in a real SwiftUI app!</p><p>Singletons aren’t the enemy. <strong>Bad architecture is.</strong></p><p>The pattern itself is fine. What matters is:</p><ol><li><strong>What you put in it</strong> (thin coordination, not heavy logic)</li><li><strong>How you access it</strong> (through protocols, not directly)</li><li><strong>Where it lives</strong> (appropriate thread context)</li><li><strong>How do you test it</strong> (dependency injection, not global state)</li></ol><p>A well-designed Singleton becomes an invisible, reliable piece of infrastructure.</p><p>A poorly-designed one becomes technical debt that slows your entire team.</p><p><strong>Choose and use wisely.</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b0fc4938e767" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Running Swift & SwiftUI Code in Android Applications with Skip Tool: A Practical Guide]]></title>
            <link>https://medium.com/@iosdev.priyank/running-swift-swiftui-code-in-android-applications-with-skip-tool-a-practical-guide-4796f0863b99?source=rss-4cf4c83bdd7e------2</link>
            <guid isPermaLink="false">https://medium.com/p/4796f0863b99</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Priyank Gandhi]]></dc:creator>
            <pubDate>Wed, 04 Sep 2024 04:38:40 GMT</pubDate>
            <atom:updated>2024-09-04T04:38:40.519Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Skip</strong> is a new technology for building native iOS and Android apps, tailored for the iOS-first app ecosystem. Development is done in Xcode using Swift and SwiftUI, while Skip automatically generates the equivalent Android code.</p><ul><li><strong>Goal</strong>: Skip aims to blend into the background, offering an uncompromised iOS development experience as its Xcode plugin manages the Android version.</li><li><strong>Core Technology</strong>: At the core of Skip is an intelligent Swift to Kotlin transpiler, utilizing Apple’s SwiftSyntax library — the same used in Swift macros — to parse Swift source code.</li><li><strong>Output</strong>: The transpiler converts Swift code into clean, human-readable Kotlin, often indistinguishable from hand-written Kotlin, with even comments preserved.</li><li><strong>Special Handling</strong>: SwiftUI is transpiled into Compose, although some Swift compiler magic cannot be fully replicated in Kotlin.</li></ul><h3>Here’s how to do it:</h3><h4>Step 1: Install Skip Tools on macOS</h4><p>Open the Terminal application and run the following command to install Skip tools on your machine:<br>brew install skiptools/skip/skip</p><h4>Step 2: Register on the Website (Optional)</h4><ul><li><strong>Free Trial</strong>: Skip offers a 14-day free trial, which starts automatically upon installation.</li><li><strong>Evaluation License</strong>: As the trial period ends, Skip will prompt you to obtain a free evaluation license from <a href="https://skip.tools/eval">this link</a>.</li><li><strong>License Purchase</strong>: Before the evaluation period ends, Skip will remind you to purchase a license online. Visit the pricing page to select the appropriate license.</li><li><strong>Node-Locked License</strong>: Each license key is tied to a single machine, requiring the output of the skip hostid command.</li><li><strong>Registration</strong>: To get started, register on the Skip website by visiting <a href="https://skip.tools/pricing/">this link</a> and selecting a plan. You’ll need to enter your name, email address, and optionally, your organization name. Additionally, you must provide a host identifier, which can be obtained by running the following command in the Terminal:<br>skip hostid<br> After agreeing to the terms, you will receive your license key via the registered email address.</li></ul><h4>Step 3: Set Up the License Key</h4><p>To set up the license key in your macOS environment, create a file in the Skiptools directory if it doesn’t already exist:</p><p>touch ~/.skiptools/skipkey.env</p><p>Next, open the file and add the license key you received via email:</p><p>open -a TextEdit ~/.skiptools/skipkey.env</p><h4>Step 4: To check system requirements</h4><p>write the next command on a terminal to check prerequisite systems<br>skip doctor</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/1*TNa8fsYoiKSYhY5HZ32efw.png" /></figure><h4>Step 5: To Perform system Full evaluation</h4><p>write the next command on a terminal to system full evaluation <br>skip checkup</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fe-QGf7JJDb_Ne22Td6acw.png" /></figure><h4><strong>Project Setup</strong></h4><p>Now that Skip is installed and registered, you can start building a new project using Skip.</p><p>To create a new dual-platform app project, run the following command:<br>skip init --appid=bundle.id project-name AppName</p><p><strong>Note:<br></strong>The skip init the command creates a functional template app, but before you can build and launch it, an <strong>Android emulator must be running</strong>. Open Android Studio, go to the Virtual Device Manager from the ellipsis menu in the Welcome dialogue and create a device. Then, launch the emulator.</p><p>For example, let’s create a project using the following command:</p><p>skip init --appid=com.amp.swiftskip Swift-Skip SwiftSkip</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CE1ZxCgTMzxw8wMeQTyFiA.png" /></figure><ul><li><strong>Project Name</strong>: Swift-Skip</li><li><strong>Application Name</strong>: SwiftSkip</li><li><strong>Directory Structure</strong>: Running the command will create a Swift-Skip/ folder.</li><li><strong>SwiftPM Package</strong>: Inside the folder, you’ll find a new SwiftPM package containing a single module named SwiftSkip.</li><li><strong>Platform-Specific Folders</strong>: The folder will include both Darwin and Android directories.</li><li><strong>Configuration File</strong>: A shared Skip.env app configuration file will be generated.</li><li><strong>Darwin Folder</strong>: Within the Darwin folder, there will be a SwiftSkip.xcodeproj project with a SwiftSkip target, which can be opened in Xcode.</li></ul><p>You can also open the project in Xcode immediately by using:</p><p>skip init --open-xcode --appid=com.amp.swiftskip Swift-Skip SwiftSkip</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OxNtfk6GlMap5UtkW_WECg.png" /></figure><h3>Conclusion</h3><p>With Skip, you’ve streamlined the process of building dual-platform apps, starting from installation to project setup. By using a simple command, you create a robust project structure with everything you need to develop for both iOS and Android seamlessly. From the initial setup to launching your app in Xcode and Android Studio, Skip handles the heavy lifting, allowing you to focus on what you do best — coding.</p><p><strong>Whoo-hoo!</strong> You’re all set to dive into your project. Happy coding! 🎉</p><p>If you found this guide helpful, please follow and clap! 👏</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4796f0863b99" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mastering Xcode Watchpoints: Advanced Debugging Technique]]></title>
            <link>https://medium.com/@iosdev.priyank/mastering-xcode-watchpoints-advanced-debugging-technique-fd935f7bfa39?source=rss-4cf4c83bdd7e------2</link>
            <guid isPermaLink="false">https://medium.com/p/fd935f7bfa39</guid>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[debugging]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios-development]]></category>
            <dc:creator><![CDATA[Priyank Gandhi]]></dc:creator>
            <pubDate>Sat, 03 Aug 2024 04:34:54 GMT</pubDate>
            <atom:updated>2024-08-10T13:54:43.905Z</atom:updated>
            <content:encoded><![CDATA[<p>Debugging is a crucial part of development, and most people are familiar with using breakpoints to debug code in Xcode. Xcode also offers powerful tools for debugging, including watchpoints. Watchpoints let you monitor changes to a variable’s value while your program runs. In this post, we’ll look closely at watchpoints with practical examples to show you how to use them effectively.</p><p><strong>What are watchpoints?</strong><br>Watchpoints are breakpoints that pause your program when the value of a specific variable changes. They are useful for finding out which part of your code changes the variable’s value, helping you track down and fix bugs more effectively.</p><p><strong>How do I set watchpoints?</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/702/1*og0BKbRnZpqD2VGmnj_JaQ.gif" /></figure><h3>Step-by-Step Debugging with Watchpoints</h3><ol><li><strong>Set a Breakpoint:</strong> Set a breakpoint at the line let calculator = Calculator() to pause the execution before the total a variable is modified.</li><li><strong>Run and Pause:</strong> Run the application. Execution will pause at the breakpoint.</li><li><strong>Set a Watchpoint:</strong> Locate the total variable under the calculator object in the debug area. Right-click on total and select “Watch.”</li><li><strong>Continue Execution:</strong> Continue running the application by clicking the Continue button or pressing Cmd + Ctrl + Y. The application will run until the total variable is modified.</li><li><strong>Observe Watchpoint Trigger:</strong> When the total a variable is incremented or decremented, Xcode will pause execution, allowing you to inspect the state of your application at that point.</li></ol><h4><strong>Manually set watchpoints in LLDB</strong></h4><ul><li>Set a breakpoint where the variable is in scope.</li><li>When the execution pauses at the breakpoint, open the LLDB console (bottom of the debug area).</li><li>Enter the following command: <br>watchpoint set variable calculator.total<strong> or <br></strong>w s v calculator.total</li><li>Continue running the application. The execution should pause when total changes are made.</li></ul><h4><strong>Final Output</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/524/1*qnrjW40QCsO84YTr7qCHIg.gif" /><figcaption>After setting a watchpoint on ‘total,’ execution halts every time ‘total’ is updated.</figcaption></figure><p><strong>Note: </strong>Watchpoints need to be set each time you launch your app, as they are not persistent like breakpoints</p><h3>Conclusion</h3><p>Watchpoints are a powerful tool in Xcode for tracking down bugs related to variable modifications. By setting watchpoints, you can pause the execution of your program exactly when a variable’s value changes, providing valuable insights into your application’s behaviour.</p><p>In this blog post, we’ve covered the basics of watchpoints and how to set them up in Xcode. We also walked through a simple example to demonstrate their use. By incorporating watchpoints into your debugging toolkit, you can streamline the process of identifying and fixing bugs, ultimately leading to more robust and reliable code.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fd935f7bfa39" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Effortless Tips for Resolving .pbxproj Merge Issues in Xcode]]></title>
            <link>https://medium.com/@iosdev.priyank/effortless-tips-for-resolving-pbxproj-merge-issues-in-xcode-2157508c0e25?source=rss-4cf4c83bdd7e------2</link>
            <guid isPermaLink="false">https://medium.com/p/2157508c0e25</guid>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Priyank Gandhi]]></dc:creator>
            <pubDate>Fri, 05 Apr 2024 10:41:09 GMT</pubDate>
            <atom:updated>2024-04-05T10:53:13.404Z</atom:updated>
            <content:encoded><![CDATA[<h3>Effortless Tips for Resolving .pbxproj Merge Issues in Xcode</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3pCn4choS3gWIH2BHuDQ0g.png" /></figure><p>Merge conflicts in Xcode .pbxproj files can be a headache for developers, often leading to frustration and wasted time. Resolving these conflicts in Xcode after merging code changes can sometimes feel like hitting a wall. However, navigating through .pbxproj merge information can be a smooth process if you have the right technique and knowledge.</p><p>In this blog post, we will explore developers&#39; most common challenges when resolving .pbxproj conflicts and provide practical ways to overcome them.</p><p>Join us as we fix complex .pbxproj decisions in Xcode, turning what once seemed like an unmanageable task into a manageable effort. Let’s get in and make your development work better today!</p><p>Step 1: Install a <a href="https://brew.sh/">homebrew</a>, If you have not found it in your machine.</p><p>Step 2: Install a <a href="https://github.com/Serchinastico/Kin">kin</a> library usingbrew install kin</p><p>Step 3: Go to your project folder in the terminal and type kin<br>Using Kin from your Xcode project directory. Kin will automatically detect where your project configuration is located and check whether it is correct.</p><pre>ERROR: line 7166:2 mismatched input &#39;B2AE182B871767008BAE99&#39; expecting &#39;sourceTree&#39;</pre><pre>ERROR: line 400:3 mismatched input &#39;)&#39; expecting &#39;inputPaths&#39;</pre><p>Now you can go to your favourite editor and update the error detected by the Kin.</p><p>Time saver information &amp; Happy Coding !!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2157508c0e25" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Live Previews with UIKit in iOS]]></title>
            <link>https://medium.com/@iosdev.priyank/live-previews-with-uikit-in-ios-a4dd2bb24f70?source=rss-4cf4c83bdd7e------2</link>
            <guid isPermaLink="false">https://medium.com/p/a4dd2bb24f70</guid>
            <category><![CDATA[uikit]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[ui-design]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Priyank Gandhi]]></dc:creator>
            <pubDate>Thu, 15 Feb 2024 11:59:26 GMT</pubDate>
            <atom:updated>2024-02-15T11:59:26.578Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*vMWT-6xTTVUDBY3agnTAMg.gif" /><figcaption>Watch for the login button; I’ve updated the code, and the changes are now visible in the live preview.</figcaption></figure><h3><strong>Introduction:</strong></h3><p>In the dynamic world of iOS development, creating a live preview screen is a valuable skill that enables developers to showcase their app’s interface in real-time. This blog will guide you through the process of creating a live preview screen using UIViewController and UIView with programmatically applied constraints, allowing for a responsive and visually engaging user interface.</p><h3>UIViewController Preview Extension</h3><pre>import SwiftUI<br><br>extension UIViewController {<br>    <br>    private struct ControllerPreview: UIViewControllerRepresentable {<br>        let viewcontroller: UIViewController<br>        <br>        func makeUIViewController(context: Context) -&gt; some UIViewController {<br>            return viewcontroller<br>        }<br>        <br>        func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {<br>            <br>        }<br>        <br>    }<br>    <br>    func showLivePreview() -&gt; some View {<br>        ControllerPreview(viewcontroller: self)<br>    }<br>    <br>}</pre><h3>UIView Preview Extension</h3><pre>import SwiftUI<br><br>extension UIView {<br>    private struct ViewPreview: UIViewRepresentable {<br>        typealias UIViewType = UIView<br>        let view: UIView<br>        func makeUIView(context: Context) -&gt; UIView {<br>            return view<br>        }<br>        <br>        func updateUIView(_ uiView: UIView, context: Context) {<br>            <br>        }<br>    }<br>    <br>    func showLivePreview() -&gt; some View {<br>        ViewPreview(view: self)<br>    }<br>}</pre><p>Indeed, it’s incredibly useful; you can now check live previews of UIKit by simply adding a small chunk of code.</p><pre>import SwiftUI<br><br>/// UIViewController<br> <br>#Preview {<br>    UIViewController().showLivePreview()<br>}<br><br>/// UIView<br><br>#Preview {<br>    UIView().showLivePreview()<br>}</pre><p>“You can utilize the provided code for each class and display a live preview side by side. In the live preview, you can apply constraints programmatically.</p><p>Usage Example: For instance, if you create a LoginViewController class:</p><pre>LoginViewController().showLivePreview()</pre><p>Similarly, if you create a BannerView class:</p><pre>BannerView().showLivePreview()</pre><p>It’s worth noting that programmatically managing constraints becomes significantly easier in such cases. Moreover, I recommend utilizing the <a href="https://github.com/SnapKit/SnapKit">SnapKit</a> library for straightforward constraint handling.</p><p>I have shared the code for the demonstrated GIF on <a href="https://github.com/iosdevpriyank/UIKitLivePreview">GitHub</a>, allowing you to download and understand it.</p><p>Happy Coding :) :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a4dd2bb24f70" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mastering Reactive Programming with Combine Framework in Swift ( Part 1: Theoretical Concept)]]></title>
            <link>https://medium.com/@iosdev.priyank/mastering-reactive-programming-with-combine-framework-in-swift-part-1-theoretical-concept-e27adb0ee188?source=rss-4cf4c83bdd7e------2</link>
            <guid isPermaLink="false">https://medium.com/p/e27adb0ee188</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[reactive-programming]]></category>
            <category><![CDATA[combine]]></category>
            <dc:creator><![CDATA[Priyank Gandhi]]></dc:creator>
            <pubDate>Mon, 15 Jan 2024 07:44:01 GMT</pubDate>
            <atom:updated>2024-01-16T13:38:25.270Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*llKgr9o1sgwIC71hv5lHoA.png" /></figure><h3>Introduction:</h3><p>The SwiftUI and Swift Combine frameworks have revolutionized the way developers build robust and responsive iOS applications. Combine, introduced by Apple, is a powerful framework that brings reactive programming to Swift, allowing developers to handle asynchronous events more elegantly and concisely. In this blog, we will delve deep into the Combine Framework step-by-step.</p><p>Before delving into Combine, let’s first grasp the concept of reactive programming.</p><p><strong>Reactive Programming: </strong>Reactive programming is a programming paradigm focused on handling asynchronous data streams and responding to changes in a declarative manner. In the context of a real-life example with the human body, reactive programming can be compared to the body’s automatic response when touching a hot bike silencer.</p><ul><li><strong>Asynchronous Responses:</strong> When accidentally touching a hot bike silencer, the body reacts immediately by retracting the hand to avoid injury.</li><li><strong>Declarative Nature:</strong> The response is automatic and instinctive, involving neural pathways and reflexes that prioritize self-preservation.</li></ul><p>In this scenario, the human body’s rapid and instinctive reaction to the hot bike silencer mirrors the principles of reactive programming, where responses to events happen without explicit, conscious commands.</p><h3>Key Concepts of Combine Framework</h3><p>We’ll explore the core concepts of Combine: publishers, subscribers, operators, and subjects. For each concept, we’ll provide examples with a human analogy.</p><h3>1. Publishers: The Warning Signal</h3><p>At the heart of Combine lies the concept of publishers. Publishers are entities that emit a sequence of values over time. They serve as the source of truth in a reactive data flow. Combine provides a variety of built-in publishers, and developers can create custom publishers to represent different data sources.</p><p><strong>Example: </strong><br><strong>Publishers</strong> are akin to the nervous system’s receptors in our body. Just as the skin’s nerve endings detect heat, publishers emit signals or values over time. In our scenario, the hot bike silencer serves as the source of the stimulus, triggering a warning.</p><pre>import Combine<br><br>let publisher = Just(&quot;Hot Surface Warning!&quot;)</pre><p>In this example, &#39;Just&#39; publisher emits a single value and warning message, simulating the body’s detection of a hot surface.</p><h3>2. Subscribers: Immediate Reaction</h3><p>Subscribers receive and react to the values emitted by publishers. They define what to do with the received values, handle errors, and respond to completion events. Subscribers subscribe to publishers, establishing a connection that allows them to react in real time to changes in the data stream.</p><p><strong>Example:<br>Subscribers</strong> are comparable to the body’s reflexes — immediate responses to a stimulus. They receive and react to the emitted values. In our analogy, the body’s reflexes represent the subscribers.</p><pre>let cancellable = publisher.sink { warningMessage in<br>    print(&quot;Reacting to Warning: \(warningMessage)&quot;)<br>}</pre><p>In this example, &#39;Sink&#39; attaches a subscriber to the publisher, warning message emitted by the publisher.</p><h3>3. Operators: Adaptive Responses</h3><p>Combine provides a rich set of operators for transforming, filtering, and combining values emitted by publishers. These operators allow developers to manipulate data flows in a declarative and concise manner. Operators chain together, enabling the creation of complex data transformations.</p><p><strong>Example:<br>Operators</strong> are like the body’s adaptive mechanisms, allowing for transformations of the emitted values. In this context, they represent how the body adjusts its reaction based on the severity of the stimulus — a form of adaptation.</p><pre>let adaptedPublisher = publisher<br>    .map { $0.lowercased() }<br>    .filter { !$0.contains(&quot;warning&quot;) }</pre><p>In this example, the &#39;map&#39; and &#39;filter&#39; operators adapt the warning message, showcasing how modify data flows.</p><h3>4. Subjects: Communication Hub</h3><p>Subjects act as both publishers and subscribers, providing a bridge between imperative and reactive code. They allow for the injection of values into a Combine pipeline. There are various types of subjects, such as PassthroughSubject and CurrentValueSubject.</p><p><strong>Example:<br>Subjects</strong> act as a communication hub, both emitting and receiving values. In our analogy, the nervous system serves as a subject, transmitting signals between different parts of the body.</p><pre><br>import Combine<br><br>let subject = PassthroughSubject&lt;String, Never&gt;()<br><br>let cancellable = subject<br>    .sink { value in<br>        print(&quot;Received Signal: \(value)&quot;)<br>    }<br><br>subject.send(&quot;Caution: Hot Surface!&quot;)</pre><p>In this example, &#39;PassthroughSubject&#39; imitates the body’s communication system, receiving and transmitting caution signals.</p><p>Now that we comprehend the type of publisher and subscription, the subsequent section will be arriving shortly.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e27adb0ee188" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swift Catalog: A Practical Guide with Examples in SwiftUI]]></title>
            <link>https://medium.com/@iosdev.priyank/swift-catalog-a-practical-guide-with-examples-in-swiftui-a319aaaaaa5a?source=rss-4cf4c83bdd7e------2</link>
            <guid isPermaLink="false">https://medium.com/p/a319aaaaaa5a</guid>
            <category><![CDATA[string-catalog]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Priyank Gandhi]]></dc:creator>
            <pubDate>Thu, 04 Jan 2024 08:01:20 GMT</pubDate>
            <atom:updated>2024-01-04T08:01:20.068Z</atom:updated>
            <content:encoded><![CDATA[<p>Navigating the world of iOS app-making means crafting apps that work well in different languages. Swift’s String Catalogs are a big help here. They handle different languages in your SwiftUI apps smoothly. I’ll guide you through Swift String Catalogs in SwiftUI in detail, using simple examples to show how they work.</p><p><a href="https://medium.com/@iosdev.priyank/swifts-language-magic-making-apps-speak-every-tongue-6e98764ecaba">In my previous article</a>, I talked about the basics of Swift catalogs—why they matter, adding files to projects, and the basics of using them. This time, we’re going practical. We’ll cover everything you need to know about Swift catalogs. I’ll present the information using a question-and-answer format for better clarity and understanding.</p><p><strong>Question:</strong> Could you guide me through using localized strings in SwiftUI?<br><strong>Answer:</strong> Sure, in SwiftUI, incorporating localized strings involves using the Text view alongsideLocalizedStringKey. When defining text within a Text view, you utilize LocalizedStringKey it to reference the localized string from your String Catalog.</p><pre>import SwiftUI<br><br>struct ContentView: View {<br>    var body: some View {<br>        VStack {<br>            Spacer()<br>            Text(&quot;Localized&quot;)<br>            Text(&quot;Welcome to the app&quot;)<br>            Spacer()<br>            Text(&quot;Not Localized&quot;)<br>            Text(verbatim: &quot;Welcome to the app&quot;)<br>            Spacer()<br>            Text(&quot;Not Localized&quot;)<br>            Text(String(&quot;Welcome to the app&quot;))<br>            Spacer()<br>        }<br>        .padding()<br>        .border(.black)<br>    }<br>}<br><br>#Preview {<br>    ContentView()<br>}<br><br><br>#Preview {<br>    ContentView().environment(\.locale, .init(identifier: &quot;fr&quot;))<br>}</pre><p>Output</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*60YMVrot_s80cA9zxbWFvw.png" /></figure><p>While your code seems correct and I understand the concept of localized strings, it appears that the output doesn’t reflect the localization of the same string.</p><p><strong>Question:</strong> Why doesn’t SwiftUI localize strings using the verbatim or String() approach?<br><strong>Answer: </strong>This occurs because SwiftUI’s Text view treats its argument as a localizable type, such as LocalizedStringKey.&quot;</p><pre>extension Text {<br>  public init(_ key: LocalizedStringKey, <br>                tableName: String? = nil, <br>                bundle: Bundle? = nil, <br>                comment: StaticString? = nil)<br>}</pre><p><strong>Question:</strong> How do I use plurals and dynamic strings in the String Catalog?<br><strong>Answer: </strong>I’ll illustrate both concepts using one example.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rISXp02019k8f9ofUv03kA.png" /><figcaption>The image above contains one string for dynamic and another for plural.</figcaption></figure><p>I’ll demonstrate how to form sentences in the plural.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cXJAdhgFL2wROKWpolqUZw.png" /><figcaption>To set the plural string, right-click on it and select ‘Vary by Plural’.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*izbLfjbDpndpLMvHfzKLMw.png" /><figcaption>Including plural when the value reaches zero.</figcaption></figure><p>Observing the image below, you can now see the resemblance.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XT5REwYi8YTW15HV4Gi1EA.png" /></figure><p>Notice how the state requires review because I’ve reviewed all strings except for the single-item string.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3RdYyOqsN5_rgi2P2mmtlg.png" /></figure><p>Observe the state: all remain ‘new’ because I haven’t translated any strings into French yet.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wYo2qZbczTEOhV5ZHWa2gw.png" /><figcaption>After translating all strings, observe the state.</figcaption></figure><p>Utilizing all string catalog strings within SwiftUI code for better understanding.</p><pre>import SwiftUI<br><br>struct ContentView: View {<br>    @State var dynamicText: String = &quot;&quot;<br>    var body: some View {<br>        VStack {<br>            Spacer()<br>            Text(&quot;Dynamic Text&quot;)<br>                .bold()<br>            TextField(&quot;What do you want to play?&quot;, text: $dynamicText)<br>                .padding()<br>                .overlay (<br>                    RoundedRectangle(cornerRadius: 14)<br>                               .stroke(Color.green, lineWidth: 2)<br>                )<br>            Text(&quot;I want to play \(dynamicText)&quot;)<br>            Spacer()<br>            Text(&quot;Plural Text&quot;)<br>                .bold()<br>            Text(&quot;You have \(0) pizza slices.&quot;)<br>            Text(&quot;You have \(1) pizza slices.&quot;)<br>            Text(&quot;You have \(2) pizza slices.&quot;)<br>            Spacer()<br>        }<br>        .padding()<br>        .frame(maxWidth: .infinity, maxHeight: .infinity)<br>    }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7msXWef4srunmAdEw23sNA.jpeg" /></figure><p><strong>Question:</strong> Explain ‘Vary by device’.<br><strong>Answer: </strong>“Vary by device” refers to the ability to adjust the display or behavior of your interface elements based on the characteristics of the device running the app. This feature allows you to adapt your app’s user interface according to different devices, such as iPhones, iPads, or Macs, ensuring a more optimized and tailored experience for each device.</p><p>I’ll illustrate with an example</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4BP-53gonxIJgVjdJoV6aw.png" /><figcaption>In the previous example, the dynamic text was chosen to ‘Vary By Device’.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LFujXCQaObADluw_xiQcrA.png" /><figcaption>The string varies across iPhones, iPads, and other devices.</figcaption></figure><p>Swift Catalog serves as a comprehensive tool within SwiftUI, offering a practical and versatile approach for managing strings and accommodating various device types. Through the provided examples, it becomes evident how this functionality streamlines the localization process and facilitates dynamic content presentation across different Apple devices. Embracing the Swift Catalog empowers developers to create more adaptable and user-friendly applications in SwiftUI, optimizing the user experience across diverse platforms effortlessly.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a319aaaaaa5a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swift’s Language Magic: Making Apps Speak Every Tongue]]></title>
            <link>https://medium.com/@iosdev.priyank/swifts-language-magic-making-apps-speak-every-tongue-6e98764ecaba?source=rss-4cf4c83bdd7e------2</link>
            <guid isPermaLink="false">https://medium.com/p/6e98764ecaba</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[string-catalog]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[string-interpolation]]></category>
            <dc:creator><![CDATA[Priyank Gandhi]]></dc:creator>
            <pubDate>Thu, 04 Jan 2024 07:59:19 GMT</pubDate>
            <atom:updated>2024-01-04T07:59:19.420Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*XPb1L3F_zMXO6W65oZVzGw.png" /><figcaption>Image source: <a href="https://www.bitrix24.in/">https://www.bitrix24.in/</a></figcaption></figure><p>In software development, managing and presenting strings efficiently within an application is crucial for internationalization and localization. In Swift, a powerful programming language developed by Apple, the String Catalog is a valuable tool used to streamline the process of handling strings for multiple languages. Let’s delve into the world of string catalogs in Swift.</p><h3>Understanding String Catalogs</h3><p>String catalogs, introduced in Xcode 15 onwards, are essentially collections of localized string resources. They allow developers to manage strings separately from the main codebase, making it easier to support multiple languages without cluttering the code.</p><h3>Benefits of String Catalogs</h3><ul><li><strong>Localization:</strong> String catalogs facilitate the process of translating and adapting an application to different languages and regions.</li><li><strong>Centralized Management:</strong> Developers can maintain all strings in one place, making it simpler to update and manage translations.</li><li><strong>Clearer Code:</strong> Using String Catalogs helps declutter the codebase by separating strings from the main code, improving readability and maintenance.</li></ul><h3>Creating a String Catalog</h3><p>Let’s explore how to create and utilize a string catalog in a Swift project:</p><h3>Step 1: Create a New String Catalog File</h3><ol><li>Open Xcode and navigate to the project navigator.</li><li>Right-click on the project folder or use the “File” menu.</li><li>Choose “New File” and select “String Catalog” from the template list.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ujTqA3NJB8thevGc3gokYA.png" /><figcaption>String Catalog</figcaption></figure><p>Name the file appropriately, likeLocalizable.xcstrings</p><h3>Step 2: Add Localized Strings</h3><ul><li>Inside the newly createdLocalizable.xcstrings file,</li><li>Open theLocalizable.xcstrings file from the left navigator in Xcode; you’ll now see the following screen.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uzD4BDpG_yr84Np5aq29SA.png" /></figure><ul><li>If you want to add language support for a multi-language application, you’ll notice that English is set as the default base language. Click on the plus sign within the same language window. You’ll now see the following screen:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aGYc96CWf3J01j7rvu_GMg.png" /></figure><ul><li>Now, add the appropriate language that you want to support for your application. You’ll now see the following screen:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*K9THjvyMplmkITDAuaGpNQ.png" /></figure><ul><li>Add strings to be displayed on a screen, then utilize a third-party translation tool to update these strings. Once updated, you’ll notice a green indicator signifying the changes.</li><li>Xcode monitors your translation progress, displaying the percentage of translated strings next to each language. This feature helps maintain focus on the task at hand by presenting a comprehensive view of entries that have been successfully translated, indicated by a green checkmark.</li></ul><p>Xcode categorizes entries based on their status, each denoting a specific meaning.</p><ul><li><strong>STALE:</strong> Indicates a string that’s no longer utilized in the code, likely deleted recently.</li><li><strong>NEW:</strong> This represents a fresh entry requiring translations to be added.</li><li><strong>NEEDS REVIEW:</strong> Allows marking entries for further review and consideration.</li><li><strong>Green Checkmark:</strong> This signifies that the entry has been translated.</li></ul><h3>Best Practices and Tips</h3><ul><li><strong>Use Descriptive Keys:</strong> Employ keys that are descriptive and easily recognizable to avoid confusion while managing multiple strings.</li><li><strong>Test Localization:</strong> Always test the app with different language settings to ensure that all strings are properly localized.</li><li><strong>Update String Catalogs Regularly:</strong> Keep the String Catalog updated with new strings and translations as the app evolves.</li></ul><h3>Conclusion</h3><p>String catalogs in Swift are a powerful tool for managing and localizing strings in applications. They simplify the process of adapting an app to different languages, enabling developers to provide a more inclusive and accessible user experience. By using string catalogs efficiently, developers can create applications that resonate with a global audience, breaking language barriers and expanding their reach.</p><p>For a better understanding of string catalog and how to use it in SwiftUI with practicality, <a href="https://medium.com/@iosdev.priyank/swift-catalog-a-practical-guide-with-examples-in-swiftui-a319aaaaaa5a">click on it</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6e98764ecaba" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>