<?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"><channel><title><![CDATA[Sajid's iOS Blog]]></title><description><![CDATA[Everything you need to build and grow on iOS. Deep dives into Swift development and advanced App Store Optimization (ASO) strategies for developers and product managers who want to scale.]]></description><link>https://blog.sajidhasan.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1769180832768/a7880e57-ab08-46a2-a4cb-169742a0af35.png</url><title>Sajid&apos;s iOS Blog</title><link>https://blog.sajidhasan.com</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 14 May 2026 08:07:13 GMT</lastBuildDate><atom:link href="https://blog.sajidhasan.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[From ObservableObject to @Observable Macro: SwiftUI State Guide]]></title><description><![CDATA[Have you ever looked at a SwiftUI view and wondered why it was refreshing when it should not have been? You are not alone. This often happens because the older observation system in SwiftUI is a blunt]]></description><link>https://blog.sajidhasan.com/swiftui-observable-macro-migration-guide</link><guid isPermaLink="true">https://blog.sajidhasan.com/swiftui-observable-macro-migration-guide</guid><category><![CDATA[SwiftUI]]></category><category><![CDATA[Swift]]></category><category><![CDATA[swiftui tutorial ]]></category><category><![CDATA[observable]]></category><category><![CDATA[iOS]]></category><category><![CDATA[State Management ]]></category><category><![CDATA[iOS development]]></category><category><![CDATA[Bindable]]></category><category><![CDATA[From ObservableObject to @Observable Macro: SwiftUI State Guide]]></category><category><![CDATA[modern SwiftUI patterns]]></category><category><![CDATA[Observable macro]]></category><category><![CDATA[ObservableObject]]></category><category><![CDATA[ObservableObject vs Observable]]></category><category><![CDATA[passing data to child view SwiftUI]]></category><category><![CDATA[swiftui macro]]></category><category><![CDATA[SwiftUI performance]]></category><category><![CDATA[SwiftUI performance tips]]></category><category><![CDATA[swiftui state management]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Tue, 24 Feb 2026 03:35:00 GMT</pubDate><enclosure url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/630faec575af73ad1f0620a9/b1b64588-d636-41c6-a8b6-ed29173233db.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever looked at a SwiftUI view and wondered why it was refreshing when it should not have been? You are not alone. This often happens because the older observation system in SwiftUI is a blunt instrument. It notifies the view that something changed but it does not specify what. Understanding the new observation system can save you hours of debugging and make your apps feel significantly more responsive.</p>
<p>For years, ObservableObject and @Published were the standard way to connect your data models to your UI. With the release of iOS 17, Apple introduced the @Observable macro. This change simplifies how you write code while making your applications faster and cleaner.</p>
<h2>The Old Way: ObservableObject</h2>
<p>In the older system, you had to manually mark every property you wanted to track.</p>
<pre><code class="language-swift">class ProfileViewModel: ObservableObject {
    @Published var name: String = ""
    @Published var age: Int = 25

    // Must mark every property manually
}

struct ProfileView: View {
    @StateObject var viewModel = ProfileViewModel()

    var body: some View {
        Text(viewModel.name)
    }
}
</code></pre>
<h3><strong>Drawbacks of this approach</strong></h3>
<ul>
<li><p>You must remember to mark every single property with @Published</p>
</li>
<li><p>If you change the age property, the Text view for name still re-renders</p>
</li>
<li><p>Boilerplate code increases as your models grow in complexity</p>
</li>
<li><p>Managing @StateObject versus @ObservedObject can be confusing for beginners</p>
</li>
</ul>
<h2>The New Way: The @Observable Macro</h2>
<p>The new system is smarter. It tracks which properties are actually being read by the view and only triggers a refresh when those specific values change.</p>
<pre><code class="language-swift">@Observable
class Profile {
    var name: String = ""
    var age: Int = 25
}

struct ProfileView: View {
    @State var profile = Profile()

    var body: some View {
        VStack {
            Text(profile.name)
            TextField("Change name", text: $profile.name)
        }
    }
}
</code></pre>
<h3><strong>Benefits of @Observable</strong></h3>
<ul>
<li><p>All properties are automatically observed without extra keywords</p>
</li>
<li><p>Views only re-render when a property they specifically use is modified</p>
</li>
<li><p>You can use the standard @State and @Bindable wrappers</p>
</li>
<li><p>It reduces memory overhead and improves app performance</p>
</li>
</ul>
<h2>Passing Data to Child Views: The @Bindable Wrapper</h2>
<p>When you break your UI into smaller reusable components, you will inevitably need to pass your state down to a child view. In the legacy system, you would rely on @ObservedObject. With the new macro, the workflow changes slightly.</p>
<p>Here is exactly how you pass an observable object down the view hierarchy and create a two-way connection for editing.</p>
<pre><code class="language-swift">@Observable
class UserSettings {
    var username: String = "Guest"
}

struct ParentView: View {
    // 1. Initialize the state in the parent
    @State var settings = UserSettings()

    var body: some View {
        VStack {
            Text("Welcome, \(settings.username)")
            
            // 2. Pass the object directly
            ChildEditView(settings: settings)
        }
    }
}

struct ChildEditView: View {
    // 3. Receive the object using @Bindable
    @Bindable var settings: UserSettings

    var body: some View {
        // 4. Use the $ syntax to create a two-way binding
        TextField("Edit Username", text: $settings.username)
            .textFieldStyle(.roundedBorder)
    }
}
</code></pre>
<h3><strong>How it works</strong></h3>
<p>Notice that <code>ParentView</code> creates the object using the <code>@State</code> wrapper. When it passes <code>settings</code> to <code>ChildEditView</code>, it simply passes the object instance directly.</p>
<p>Inside <code>ChildEditView</code>, we receive that object using the <code>@Bindable</code> property wrapper. This step is critical. The <code>@Bindable</code> wrapper does one specific job: it unlocks the ability to use the <code>$</code> prefix. Without <code>@Bindable</code>, you could read the properties just fine, but you could not pass them to UI controls like a <code>TextField</code> or <code>Toggle</code> that require a two-way binding to modify the data.</p>
<h2>ObservableObject vs. @Observable</h2>
<table style="min-width:75px"><colgroup><col style="min-width:25px"></col><col style="min-width:25px"></col><col style="min-width:25px"></col></colgroup><tbody><tr><td><p><strong>Feature</strong></p></td><td><p><strong>ObservableObject</strong></p></td><td><p><strong>@Observable</strong></p></td></tr><tr><td><p><strong>Minimum iOS</strong></p></td><td><p>iOS 13</p></td><td><p>iOS 17</p></td></tr><tr><td><p><strong>Property Marking</strong></p></td><td><p>Manual @Published</p></td><td><p>Automatic</p></td></tr><tr><td><p><strong>Observation Level</strong></p></td><td><p>Entire Object</p></td><td><p>Individual Property</p></td></tr><tr><td><p><strong>View Refresh</strong></p></td><td><p>Less Efficient</p></td><td><p>Highly Optimized</p></td></tr><tr><td><p><strong>Property Wrapper</strong></p></td><td><p>@StateObject</p></td><td><p>@State</p></td></tr><tr><td><p><strong>Child Wrapper</strong></p></td><td><p>@ObservedObject</p></td><td><p>@Bindable</p></td></tr></tbody></table>

<h2>Why Developers Still Use the Old System</h2>
<p>Even though the new macro is superior, you will still see ObservableObject in many projects for a few key reasons. The most obvious is compatibility, since many apps still need to support iOS 15 or 16. Additionally, large legacy projects built on the Combine framework may require significant refactoring to switch.</p>
<p>A common strategy today is to keep your existing models as they are while using the @Observable macro for any new features you build. This allows for a gradual migration without breaking your entire codebase.</p>
<hr />
<p>Switching to @Observable makes your SwiftUI apps cleaner and more predictable. It represents the modern approach to state management by removing the need for manually published properties and providing surgical precision for UI updates.</p>
]]></content:encoded></item><item><title><![CDATA[ASO Algorithm 101: How Apple and Google Rank Apps | ASO Blueprint #4]]></title><description><![CDATA[The app store algorithm is not just a search engine. It is a decision engine. Every time a user types a word, the algorithm must decide which app deserves the top spot. In 2026, these systems are incr]]></description><link>https://blog.sajidhasan.com/aso-blueprint-4-algorithm-ranking-factors</link><guid isPermaLink="true">https://blog.sajidhasan.com/aso-blueprint-4-algorithm-ranking-factors</guid><category><![CDATA[ASO]]></category><category><![CDATA[ASO Tips]]></category><category><![CDATA[ASO Blueprint]]></category><category><![CDATA[app visibility in AI search]]></category><category><![CDATA[App Search Visibility]]></category><category><![CDATA[App Store Metadata Weights]]></category><category><![CDATA[App Store Optimization Guide]]></category><category><![CDATA[App Store Ranking Factors]]></category><category><![CDATA[App Store vs Google Play ASO]]></category><category><![CDATA[App Title Character Limits]]></category><category><![CDATA[ASO Algorithm 101]]></category><category><![CDATA[ASO Algorithm 101: How Apple and Google Rank Apps | ASO Blueprint #4]]></category><category><![CDATA[Conversion Rate Optimization for Apps]]></category><category><![CDATA[Google Play Description SEO]]></category><category><![CDATA[Google Play Store Algorithm]]></category><category><![CDATA[iOS App Store Keyword Field]]></category><category><![CDATA[Localized Product Pages]]></category><category><![CDATA[Metadata Indexing Differences]]></category><category><![CDATA[Mobile App Indexing]]></category><category><![CDATA[Organic App Growth Strategy]]></category><category><![CDATA[Organic Download Growth]]></category><category><![CDATA[Search Ads Popularity Index]]></category><category><![CDATA[Subtitles vs Short Descriptions]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Sun, 22 Feb 2026 03:35:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1771475447419/861d2e65-bab6-4c8e-a441-4e56989e9b56.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The app store algorithm is not just a search engine. It is a decision engine. Every time a user types a word, the algorithm must decide which app deserves the top spot. In 2026, these systems are incredibly smart. They follow a strict set of technical rules while prioritizing user satisfaction. To grow your app, you must understand the ASO Algorithm, technical constraints and the ranking logic of these digital brains.</p>
<hr />
<h2><strong>What’s Inside This Chapter:</strong></h2>
<ul>
<li><p><strong>Decoding the Algorithm:</strong> How Apple and Google use Relevance, Quality, and Conversion to rank your app.</p>
</li>
<li><p><strong>‘App Store vs Play Store’ Cheat Sheet:</strong> A side-by-side comparison of <strong>indexing rules</strong>, character limits, and metadata weights.</p>
</li>
<li><p><strong>Ranking Timelines:</strong> Why the App Store reflects changes in 24 hours while Google Play takes weeks.</p>
</li>
<li><p><strong>The 2-Week ASO Measurement Rule:</strong> A step-by-step framework to track organic growth and prove your strategy works.</p>
</li>
<li><p><strong>Keyword Indexation Secrets:</strong> Why your iOS description is for humans, but your Android description is for the algorithm.</p>
</li>
</ul>
<hr />
<blockquote>
<p><em><strong>If you feel confused about ASO terms and vocab, you can check out the <mark>ASO Dictionary</mark> from</strong></em> <a href="https://blog.sajidhasan.com/aso-blueprint-2-dictionary-vocabulary"><em><strong>ASO Blueprint #2.</strong></em></a></p>
</blockquote>
<hr />
<h2><strong>1. The Ranking Factors: Strong vs. Medium Influence</strong></h2>
<p>Not all data influences rankings equally. The algorithm prioritizes factors in a specific hierarchy.</p>
<h3><strong>STRONG Influence:</strong></h3>
<ul>
<li><p><strong>App Title:</strong> This remains the single strongest ranking signal for both stores.</p>
</li>
<li><p><strong>Localized Product Page:</strong> Customizing your page for different regions significantly boosts visibility.</p>
</li>
<li><p><strong>Conversion (Installs per Keyword):</strong> If users search for a term and click your app, you win that keyword.</p>
</li>
<li><p><strong>Ratings:</strong> High star ratings are a gatekeeper for high volume visibility.</p>
</li>
</ul>
<h3><strong>MEDIUM Influence:</strong></h3>
<ul>
<li><p><strong>Download Velocity:</strong> The algorithm loves freshness and recent spikes in installs.</p>
</li>
<li><p><strong>App Performance:</strong> Stores actively downrank apps with high crash rates or battery drain issues.</p>
</li>
<li><p><strong>User Reviews:</strong> While important for conversion, they are a medium ranking factor on their own.</p>
</li>
</ul>
<h3><strong>2. Apple vs. Google: The Indexing Split</strong></h3>
<p>The indexing rules determine how the store reads your app. You must treat them differently to succeed.</p>
<table>
<thead>
<tr>
<th><strong>Feature</strong></th>
<th><strong>Apple App Store (iOS)</strong></th>
<th><strong>Google Play Store (Android)</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>App Title</strong></td>
<td><strong>30 Characters</strong> (Indexed)</td>
<td><strong>30 Characters</strong> (Indexed)</td>
</tr>
<tr>
<td><strong>Subtitle</strong></td>
<td><strong>30 Characters</strong> (Indexed)</td>
<td><strong>N/A</strong></td>
</tr>
<tr>
<td><strong>Short Description</strong></td>
<td><strong>N/A</strong></td>
<td><strong>80 Characters</strong> (Indexed)</td>
</tr>
<tr>
<td><strong>Long Description</strong></td>
<td><strong>4,000 Characters</strong> (NOT Indexed)</td>
<td><strong>4,000 Characters</strong> (Fully Indexed)</td>
</tr>
<tr>
<td><strong>Keyword Density</strong></td>
<td>Low importance</td>
<td>High importance</td>
</tr>
<tr>
<td><strong>Keyword Field</strong></td>
<td><strong>100 Characters</strong> (Indexed)</td>
<td><strong>N/A</strong> (Does not exist)</td>
</tr>
</tbody></table>
<h3><strong>Strategic Takeaway:</strong></h3>
<ul>
<li><p><strong>Apple App Store (iOS):</strong></p>
<ul>
<li><p><strong>Focus:</strong> Title (30 chars), Subtitle (30 chars), and Keyword Field.</p>
</li>
<li><p><strong>Strategy:</strong> Use unique keywords; <mark>do not repeat words from the title/subtitle</mark> in the keyword field.</p>
</li>
</ul>
</li>
<li><p><strong>Google Play Store (Android):</strong></p>
<ul>
<li><p><strong>Focus:</strong> Title (30 chars), Short Description (80 chars), and Long Description (up to 4,000 chars).</p>
</li>
<li><p><strong>Strategy:</strong> Focus on keyword density (1 time per 250 characters is a safe bet). The algorithm is smarter and understands synonyms better.</p>
</li>
</ul>
</li>
</ul>
<h2><strong>3. The ‘Time to Impact’ Gap</strong></h2>
<p>The stores digest your metadata updates at different speeds. Patience is a necessary metric.</p>
<ul>
<li><p><strong>Apple App Store:</strong> Changes are often visible and reflected in rankings <strong>the next day</strong>.</p>
</li>
<li><p><strong>Google Play:</strong> It typically takes <strong>one to two weeks</strong> for the system to re-index your app and adjust your position.</p>
</li>
</ul>
<hr />
<h2><strong>The ASO Blueprint Action Plan</strong></h2>
<h3><strong>1. The 2-Week Measurement Rule</strong></h3>
<p>The easiest way to see if your ASO worked is to compare organic downloads. Focus on two intervals. Look at the <strong>2 weeks before</strong> your update and compare them to the <strong>2 weeks after</strong>. If you see significant organic growth, your strategy is correct.</p>
<h3><strong>2. Focus on the Semantic Core</strong></h3>
<p>Users <mark>search for apps by describing features or services</mark>. Start your keyword selection with a semantic core rather than just suggestions. Use tools to find traffic indicators for your selected terms.</p>
<h3><strong>3. Maintain Technical Health</strong></h3>
<p>A buggy app will never rank first. Regularly check your developer console and Crashlytics for performance issues. Stable and fast apps are prioritized by the modern algorithm.</p>
<hr />
<p>Mastering the basics of the algorithm is your foundation. See you <mark>next </mark> <strong><mark>Sunday</mark></strong> for the next part of the blueprint. We will explore the massive shifts in ASO Blueprint #5. The <mark>ASO in </mark> <strong><mark>iOS 26 AI Era</mark></strong>. We will learn how to rank when the AI is the gatekeeper.</p>
<p>If you need any further review or ASO consultancy, you can contact me directly at <a href="mailto:hello@sajidhasan.com"><strong>hello@sajidhasan.com</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[Brand vs. Generic Keywords | ASO Blueprint #3]]></title><description><![CDATA[If you only focus on your app's name, you're missing the "Discovery" engine that fuels organic growth. The secret to modern app growth is understanding user intent. Analyzing the breakdown of generic and brand keywords is vital when you optimize your...]]></description><link>https://blog.sajidhasan.com/aso-blueprint-brand-vs-generic-keywords</link><guid isPermaLink="true">https://blog.sajidhasan.com/aso-blueprint-brand-vs-generic-keywords</guid><category><![CDATA[ASO Keyword Strategy]]></category><category><![CDATA[Brand vs Generic Keywords]]></category><category><![CDATA[App Brand Defense Strategy]]></category><category><![CDATA[Generic keyword conversion rates ASO]]></category><category><![CDATA[How to rank for generic keywords in App Store]]></category><category><![CDATA[ASO metadata optimization guide]]></category><category><![CDATA[Long-tail keywords for mobile apps]]></category><category><![CDATA[Brand vs Generic Keywords | ASO Blueprint #3]]></category><category><![CDATA[App Store Optimization 2026]]></category><category><![CDATA[ASO]]></category><category><![CDATA[ASO Tips]]></category><category><![CDATA[ASO Blueprint]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Sat, 14 Feb 2026 07:51:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1771153013828/04bb7773-2542-4b98-a9aa-d902a86516b9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you only focus on your app's name, you're missing the "Discovery" engine that fuels organic growth. The secret to modern app growth is understanding user intent. Analyzing the breakdown of generic and brand keywords is vital when you optimize your app metadata. This guide provides the exact framework you need to balance your brand identity with the products and services you offer. Most app store traffic comes from brand keywords where users search for a specific name. However, your growth potential lies in generic keywords where users look for solutions instead of names. You will learn how to protect your brand identity while launching an offense to steal market share.</p>
<hr />
<h2 id="heading-whats-inside-this-chapter"><strong>What’s Inside This Chapter:</strong></h2>
<ul>
<li><p><strong>The Identity Pillar:</strong> Why Brand Defense is mandatory in 2026.</p>
</li>
<li><p><strong>The Discovery Engine:</strong> How to win Generic searches without a million-dollar budget.</p>
</li>
<li><p><strong>The Siphon Effect:</strong> Why big brands dominate and how you can pivot.</p>
</li>
<li><p><strong>The Action Plan:</strong> A step by step checklist for your next update.</p>
</li>
</ul>
<hr />
<h2 id="heading-brand-keywords"><strong>Brand Keywords</strong></h2>
<p>Brand keywords are searches for your specific app name (e.g., "Instagram") or your company.</p>
<ul>
<li><p><strong>User Intent:</strong> Navigational. They are looking for <em>you</em>.</p>
</li>
<li><p><strong>Conversion Rate (CVR):</strong> Extremely high, typically <strong>50% - 80%</strong>.</p>
</li>
<li><p><strong>The Challenge:</strong> Competitors are getting aggressive. Even if you rank #1 organically, rivals will often bid on your name in <strong>Apple Search Ads (ASA)</strong> to sit directly above your result.</p>
</li>
<li><p><strong>The Strategy:</strong> Own your name in the Title, but don't waste characters repeating it in the subtitle or keyword field. Use those precious characters for features. Your brand "Defense" ensures that when someone looks for you, they find <em>only</em> you.</p>
</li>
</ul>
<h2 id="heading-generic-keywords"><strong>Generic Keywords</strong></h2>
<p>Generic keywords describe a problem, feature, or category (e.g., "AI Photo Editor," "Budget Tracker").</p>
<ul>
<li><p><strong>User Intent:</strong> Exploratory. They have a problem, but haven't picked a winner yet.</p>
</li>
<li><p><strong>Conversion Rate (CVR):</strong> Lower than brand, typically <strong>5% - 15%</strong>, but the volume is massive.</p>
</li>
<li><p><strong>The Strategy: Semantic Relevance.</strong> Modern algorithms now prioritize "Intent Clusters" over exact keyword matches.</p>
<ul>
<li><p><strong>Avoid the "Volume Trap":</strong> Don't chase high-volume head terms like "Fitness" if you're a new app. You’ll be buried by the giants.</p>
</li>
<li><p><strong>The Pivot:</strong> Target <strong>Long-Tail Keywords</strong> (e.g., "HIIT workouts for busy moms"). These have lower competition and much higher conversion because the intent is specific.</p>
</li>
</ul>
</li>
</ul>
<hr />
<h2 id="heading-brand-vs-generic-keywords-the-comparison"><strong>Brand vs Generic</strong> Keywords<strong>: The Comparison</strong></h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Feature</strong></td><td><strong>Brand Keywords</strong></td><td><strong>Generic Keywords</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Primary Goal</strong></td><td>Retention &amp; Protection</td><td>Acquisition &amp; Discovery</td></tr>
<tr>
<td><strong>Difficulty</strong></td><td>Low (if name is unique)</td><td>High (Market competition)</td></tr>
<tr>
<td><strong>Growth Type</strong></td><td>Linear (Matches Brand Awareness)</td><td>Exponential (Market Share)</td></tr>
<tr>
<td><strong>Key Metric</strong></td><td>Share of Voice (SoV)</td><td>Category Ranking</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-the-siphon-effect-and-how-to-beat-it"><strong>The "Siphon Effect" and How to Beat It</strong></h2>
<p>Big brands often "siphon" traffic from generic terms because of their massive authority. When a user searches "Music," Spotify usually wins, not because its ASO is necessarily better, but because its <strong>Store Authority</strong> is higher.</p>
<p><strong>How to compete:</strong></p>
<ol>
<li><p><strong>Niche Down:</strong> Instead of trying to rank for "Finance," target "Freelance Expense Tracker."</p>
</li>
<li><p><strong>Visual Conversion:</strong> If you rank #5 for a generic term but your screenshots are significantly more engaging than the apps at #1-#4, the algorithm will eventually move you up because your <strong>Click-Through Rate (CTR)</strong> is higher.</p>
</li>
</ol>
<hr />
<blockquote>
<p>If you feel confused about ASO terms and vocab, you can check out the <mark>ASO Dictionary</mark> from <a target="_blank" href="https://blog.sajidhasan.com/aso-blueprint-2-dictionary-vocabulary">ASO Blueprint #2</a><a target="_blank" href="https://blog.sajidhasan.com/aso-blueprint-2-dictionary-vocabulary">.</a></p>
</blockquote>
<hr />
<h2 id="heading-the-aso-blueprint-action-plan">The ASO Blueprint <strong>Action Plan</strong></h2>
<p>To optimize your store listing this week, follow these three steps:</p>
<ol>
<li><p><strong>Stop Keyword Redundancy:</strong> Check your iOS keyword field or Google Play description. If your brand name is already in the Title, <strong>delete it</strong> from the other metadata fields. Use that space for a generic "Action" keyword instead.</p>
</li>
<li><p><strong>The Subtitle Shift:</strong> Use your Subtitle (iOS) or Short Description (Android) to house your most important <strong>Generic + Long-tail</strong> phrase.</p>
<ul>
<li><p><em>Bad:</em> "The best app for your daily life."</p>
</li>
<li><p><em>Good:</em> "Personal Budget &amp; Daily Expense Tracker."</p>
</li>
</ul>
</li>
<li><p><strong>Analyze the Split:</strong> Look at your console data. If more than 90% of your downloads are coming from "Brand" searches, you have a <strong>Discovery problem</strong>. It's time to go on the offense.</p>
</li>
</ol>
<hr />
<p>See you <mark>next </mark> <strong><mark>Sunday</mark></strong> for the next part of the blueprint. We will be diving into the "Brain" of the app stores: <strong><mark>ASO Algorithms 101</mark>,</strong> Understanding how app stores decide who stays on top.</p>
<p>If you need any further review or ASO consultancy, you can contact me directly at <a target="_blank" href="mailto:hello@sajidhasan.com"><strong>hello@sajidhasan.com</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[SOLID Principles in iOS with Swift Code Examples]]></title><description><![CDATA[Most iOS apps don’t become hard to maintain because of bad syntax or wrong APIs. They become hard because the codebase slowly turns rigid, fragile, and difficult to extend. That usually happens when SOLID is ignored. Not intentionally. Just gradually...]]></description><link>https://blog.sajidhasan.com/solid-principles-in-swift-ios</link><guid isPermaLink="true">https://blog.sajidhasan.com/solid-principles-in-swift-ios</guid><category><![CDATA[SOLID principles Swift]]></category><category><![CDATA[SOLID in iOS]]></category><category><![CDATA[Swift clean architecture]]></category><category><![CDATA[SOLID with Swift examples]]></category><category><![CDATA[iOS code best practices]]></category><category><![CDATA[Swift design principles]]></category><category><![CDATA[Dependency injection Swift]]></category><category><![CDATA[Protocol oriented programming Swift]]></category><category><![CDATA[Swift architecture patterns]]></category><category><![CDATA[Clean code Swift]]></category><category><![CDATA[iOS maintainable code]]></category><category><![CDATA[Swift protocol design]]></category><category><![CDATA[Testable Swift code]]></category><category><![CDATA[SOLID principles]]></category><category><![CDATA[solidity basics]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Tue, 10 Feb 2026 03:34:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770265933767/b9f8fef5-e746-4257-9ba0-0570bc8add37.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most iOS apps don’t become hard to maintain because of bad syntax or wrong APIs. They become hard because the codebase slowly turns rigid, fragile, and difficult to extend. That usually happens when SOLID is ignored. Not intentionally. Just gradually!</p>
<h2 id="heading-whats-inside">What’s inside?</h2>
<ul>
<li><p>What <strong>SOLID</strong> really means in the context of <strong>Swift</strong></p>
</li>
<li><p>Practical <strong>examples</strong> you can relate to in iOS projects</p>
</li>
<li><p>Common <strong>mistakes</strong> developers make while trying to “follow” SOLID</p>
</li>
<li><p>How SOLID improves testing, <strong>scalability</strong>, and team collaboration</p>
</li>
<li><p><strong>SOLID iOS Interview</strong> questions to check your real understanding</p>
</li>
</ul>
<hr />
<h2 id="heading-why-solid-matters-in-swift-projects">Why SOLID matters in Swift projects</h2>
<p>Swift gives us powerful tools: protocols, extensions, value types, generics. But without clear design principles, even modern Swift code can become messy.</p>
<p>SOLID helps you decide:</p>
<ul>
<li><p>When to create a protocol</p>
</li>
<li><p>When to split a class</p>
</li>
<li><p>How to structure dependencies</p>
</li>
<li><p>How to make features easier to extend later</p>
</li>
</ul>
<p>It is less about rules and more about writing code that survives growth. We need to use SOLID Principles for Better Swift Code in iOS Apps.</p>
<hr />
<h2 id="heading-s-single-responsibility-principle">S: Single Responsibility Principle</h2>
<p>A class should have only one reason to change.</p>
<p>In many iOS apps, ViewControllers often violate this. They fetch data, handle UI, manage state, perform navigation, and sometimes even format data.</p>
<p>When one class does too much, any small change risks breaking something unrelated.</p>
<p>Applying SRP in Swift often means:</p>
<ul>
<li><p>Moving networking to a service layer</p>
</li>
<li><p>Using ViewModels for presentation logic</p>
</li>
<li><p>Keeping ViewControllers focused on UI only</p>
</li>
</ul>
<p>This separation makes the code easier to read, test, and modify.</p>
<h3 id="heading-example">Example:</h3>
<p><strong>Problem</strong>: One class is doing too many things.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserViewController</span>: <span class="hljs-title">UIViewController</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fetchUser</span><span class="hljs-params">()</span></span> { <span class="hljs-comment">/* API call */</span> }
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">formatDate</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">String</span> { <span class="hljs-comment">/* formatting */</span> }
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">saveToCache</span><span class="hljs-params">()</span></span> { <span class="hljs-comment">/* caching */</span> }
}
</code></pre>
<p><strong>Better</strong>: Split responsibilities.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fetchUser</span><span class="hljs-params">()</span></span> { }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DateFormatterService</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">formatDate</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">String</span> { <span class="hljs-string">""</span> }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserViewController</span>: <span class="hljs-title">UIViewController</span> </span>{
    <span class="hljs-keyword">let</span> service = <span class="hljs-type">UserService</span>()
}
</code></pre>
<p>Now UI, networking, and formatting are separated.</p>
<hr />
<h2 id="heading-o-openclosed-principle">O: Open/Closed Principle</h2>
<p>Software entities should be open for extension but closed for modification. Instead of editing existing code every time a new requirement comes, you design it so new behavior can be added without touching old logic. In Swift, this is commonly achieved using protocols and protocol-oriented design.</p>
<p>For example, instead of modifying a payment class to support new methods, you define a PaymentMethod protocol and add new implementations as needed. Your existing code stays untouched, reducing risk.</p>
<h3 id="heading-example-1">Example:</h3>
<p><strong>Problem</strong>: Modifying existing class for every new case.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaymentProcessor</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">pay</span><span class="hljs-params">(type: String)</span></span> {
        <span class="hljs-keyword">if</span> type == <span class="hljs-string">"card"</span> { }
        <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> type == <span class="hljs-string">"cash"</span> { }
    }
}
</code></pre>
<p><strong>Better</strong>: Extend with protocols.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">PaymentMethod</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">pay</span><span class="hljs-params">()</span></span>
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CardPayment</span>: <span class="hljs-title">PaymentMethod</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">pay</span><span class="hljs-params">()</span></span> { }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CashPayment</span>: <span class="hljs-title">PaymentMethod</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">pay</span><span class="hljs-params">()</span></span> { }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaymentProcessor</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">process</span><span class="hljs-params">(<span class="hljs-number">_</span> method: PaymentMethod)</span></span> {
        method.pay()
    }
}
</code></pre>
<p>Add new payment types without touching old code.</p>
<hr />
<h2 id="heading-l-liskov-substitution-principle">L: Liskov Substitution Principle</h2>
<p>Subtypes must be replaceable with their base types without breaking behavior. This issue appears when subclasses change expected behavior in surprising ways.</p>
<p>For example, if a subclass overrides a method but changes what it is supposed to do, parts of the app relying on the original behavior start failing.</p>
<p>In Swift, careful protocol design and avoiding unnecessary inheritance help maintain this principle. Favor composition over inheritance whenever possible.</p>
<h3 id="heading-example-2">Example:</h3>
<p><strong>Problem</strong>: Subclass changes expected behavior.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Bird</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fly</span><span class="hljs-params">()</span></span> { }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Penguin</span>: <span class="hljs-title">Bird</span> </span>{
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fly</span><span class="hljs-params">()</span></span> {
        <span class="hljs-built_in">fatalError</span>(<span class="hljs-string">"Penguins can't fly"</span>)
    }
}
</code></pre>
<p>This breaks expectations.</p>
<p><strong>Better</strong>: Design with proper abstraction.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">Bird</span> </span>{ }

<span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">FlyingBird</span>: <span class="hljs-title">Bird</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fly</span><span class="hljs-params">()</span></span>
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Sparrow</span>: <span class="hljs-title">FlyingBird</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fly</span><span class="hljs-params">()</span></span> { }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Penguin</span>: <span class="hljs-title">Bird</span> </span>{ }
</code></pre>
<p>No broken assumptions.</p>
<hr />
<h2 id="heading-i-interface-segregation-principle">I: Interface Segregation Principle</h2>
<p>Clients should not be forced to depend on methods they do not use. Large protocols are common in iOS projects. A single delegate or manager protocol with many responsibilities forces conforming classes to implement unnecessary methods. Breaking large protocols into smaller, focused ones keeps implementations clean and reduces coupling. Swift protocols make this very natural when designed thoughtfully.</p>
<h3 id="heading-example-3">Example:</h3>
<p><strong>Problem</strong>: Fat protocol.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">Worker</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">code</span><span class="hljs-params">()</span></span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">test</span><span class="hljs-params">()</span></span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">deploy</span><span class="hljs-params">()</span></span>
}
</code></pre>
<p>Not everyone does all three.</p>
<p><strong>Better</strong>: Split protocols.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">Coder</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">code</span><span class="hljs-params">()</span></span>
}

<span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">Tester</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">test</span><span class="hljs-params">()</span></span>
}

<span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">Deployer</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">deploy</span><span class="hljs-params">()</span></span>
}
</code></pre>
<p>Classes adopt only what they need.</p>
<hr />
<h2 id="heading-d-dependency-inversion-principle">D: Dependency Inversion Principle</h2>
<p>High-level modules should not depend on low-level modules. Both should depend on abstractions. Instead of a ViewModel directly depending on a concrete API service, it should depend on a protocol.</p>
<p>This makes it easier to:</p>
<ul>
<li><p>Replace implementations</p>
</li>
<li><p>Write unit tests with mock services</p>
</li>
<li><p>Modify underlying systems without affecting business logic</p>
</li>
</ul>
<p>This is one of the most powerful principles for testable Swift code.</p>
<h3 id="heading-example-4">Example:</h3>
<p><strong>Problem</strong>: Tight coupling to concrete class.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserViewModel</span> </span>{
    <span class="hljs-keyword">let</span> api = <span class="hljs-type">APIService</span>()
}
</code></pre>
<p>Hard to test and replace.</p>
<p><strong>Better</strong>: Depend on abstraction.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">APIServiceProtocol</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fetch</span><span class="hljs-params">()</span></span>
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">APIService</span>: <span class="hljs-title">APIServiceProtocol</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fetch</span><span class="hljs-params">()</span></span> { }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserViewModel</span> </span>{
    <span class="hljs-keyword">let</span> api: <span class="hljs-type">APIServiceProtocol</span>

    <span class="hljs-keyword">init</span>(api: <span class="hljs-type">APIServiceProtocol</span>) {
        <span class="hljs-keyword">self</span>.api = api
    }
}
</code></pre>
<p>Now you can inject a mock service for testing.</p>
<hr />
<h2 id="heading-common-mistakes-when-applying-solid">Common mistakes when applying SOLID</h2>
<p>Many developers try to apply SOLID by creating too many protocols and abstractions too early. That leads to overengineering.</p>
<p>SOLID is not about adding layers. It is about removing unnecessary coupling and making future changes easier. Start simple. Introduce abstractions <strong>only when the need becomes clear</strong>.</p>
<hr />
<h2 id="heading-how-solid-improves-real-ios-development">How SOLID improves real iOS development</h2>
<p>When SOLID is applied correctly:</p>
<ul>
<li><p>Features are easier to extend</p>
</li>
<li><p>Refactoring becomes safer</p>
</li>
<li><p>Unit testing becomes simpler</p>
</li>
<li><p>Team members understand the code faster</p>
</li>
<li><p>Bugs from side effects reduce significantly</p>
</li>
</ul>
<p>Over time, the project feels organized rather than chaotic.</p>
<hr />
<h2 id="heading-frequently-asked-solid-ios-interview-questions">Frequently Asked SOLID iOS Interview Questions</h2>
<p>If you truly understand SOLID, you should be able to confidently explain and apply these in real scenarios. Try answering these yourself.</p>
<ul>
<li><p>What problem does the Single Responsibility Principle actually solve in large iOS codebases?</p>
</li>
<li><p>How would you apply the Open/Closed Principle using protocols in Swift?</p>
</li>
<li><p>Can you share a real example where violating Liskov Substitution caused bugs?</p>
</li>
<li><p>Why do large protocols become a maintenance issue, and how does Interface Segregation fix that?</p>
</li>
<li><p>How does Dependency Inversion make unit testing easier in Swift projects?</p>
</li>
<li><p>How do SOLID principles influence your choice between classes, structs, and protocols?</p>
</li>
<li><p>Which SOLID principle do you think is most commonly violated in iOS apps and why?</p>
</li>
</ul>
<p>Take time to articulate these answers from what you learned in this article. That exercise alone will prepare you far better than memorizing definitions.</p>
<hr />
<p>SOLID is a survival guide for growing codebases. Swift gives you the tools. SOLID tells you how to use them wisely. When followed properly, your code stops feeling fragile and starts feeling scalable, readable, and future-proof.</p>
<p>For further guidance or consultancy, feel free to connect at <a target="_blank" href="mailto:hello@sajidhasan.com"><strong>hello@sajidhasan.com</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[ASO Dictionary: Key Concepts and Vocabulary to be an ASO Expert | ASO Blueprint #2]]></title><description><![CDATA[In the previous chapter of the ASO Blueprint, we discussed the hidden ROI of optimization. Now, we need to lay the groundwork. You cannot build a skyscraper without understanding the blueprints, and you certainly cannot dominate the App Store charts ...]]></description><link>https://blog.sajidhasan.com/aso-blueprint-2-dictionary-vocabulary</link><guid isPermaLink="true">https://blog.sajidhasan.com/aso-blueprint-2-dictionary-vocabulary</guid><category><![CDATA[ASO Dictionary]]></category><category><![CDATA[ASO Key Concepts]]></category><category><![CDATA[App Store Optimization Vocabulary]]></category><category><![CDATA[ASO Expert Guide]]></category><category><![CDATA[App Store Marketing Terms]]></category><category><![CDATA[ASO Cheatsheet]]></category><category><![CDATA[ASO Checklist]]></category><category><![CDATA[Mobile App Analytics Terms]]></category><category><![CDATA[App Growth Strategy]]></category><category><![CDATA[ASO Dictionary: Key Concepts and Vocabulary to be an ASO Expert | ASO Blueprint #2]]></category><category><![CDATA[Increasing App Store Visibility]]></category><category><![CDATA[Improving App Conversion Rates]]></category><category><![CDATA[ASO Blueprint]]></category><category><![CDATA[ASO]]></category><category><![CDATA[ASO Tips]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Sun, 08 Feb 2026 16:02:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770284191132/1d5d9119-8365-4d4d-aea4-499a3d69f593.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the previous chapter of the ASO Blueprint, we discussed the hidden ROI of optimization. Now, we need to lay the groundwork. You cannot build a skyscraper without understanding the blueprints, and you certainly cannot dominate the App Store charts without mastering the language of ASO.</p>
<p>When you dive into app marketing, you are immediately hit with an alphabet soup of acronyms and technical jargon. Knowing the difference between organic and motivated traffic, or understanding the nuance between an impression and a product page view, is what separates those who guess from those who grow. This article serves as your fundamental dictionary. It covers the core vocabulary you need to navigate the data and make decisions that actually move the needle.</p>
<h2 id="heading-whats-inside-this-post">What’s Inside This Post</h2>
<p>In this article, we will break down the essential terminology into five distinct pillars:</p>
<ul>
<li><p><strong>Traffic Types:</strong> Understanding where your users come from.</p>
</li>
<li><p><strong>Search Mechanics:</strong> How users see your app in the store.</p>
</li>
<li><p><strong>Keyword Strategy:</strong> The difference between short-tail and long-tail.</p>
</li>
<li><p><strong>User Metrics:</strong> Measuring loyalty, views, and unique users.</p>
</li>
<li><p><strong>Business Strategy:</strong> The financial and strategic side of ASO.</p>
</li>
</ul>
<hr />
<h2 id="heading-1-decoding-traffic-sources">1. Decoding Traffic Sources</h2>
<p>Before you can optimize, you must understand where your users come from. In 2026, Store algorithms heavily factor traffic source quality into ranking signals.</p>
<ul>
<li><h3 id="heading-search-traffic"><strong>Search Traffic</strong></h3>
<p>  High-intent users who find your app by typing a specific query into the search bar. This is the primary driver for utility and service apps.</p>
</li>
<li><h3 id="heading-organic-traffic"><strong>Organic Traffic</strong></h3>
<p>  The "holy grail." These are users who find and install your app naturally without clicking on a paid advertisement.</p>
</li>
<li><h3 id="heading-incentivized-incentive-traffic"><strong>Incentivized (Incentive) Traffic</strong></h3>
<p>  Paid installs where users receive a reward (virtual currency, points) for downloading. This traffic can temporarily increase download velocity, but modern algorithms may penalize apps if this traffic doesn't lead to genuine engagement.</p>
</li>
<li><h3 id="heading-browse-app-store-explore-google-play"><strong>Browse (App Store) / Explore (Google Play)</strong></h3>
<p>  Discovery-based traffic. These users find your app via Top Charts, Category lists, or "Featured" placements (like the Today Tab).</p>
</li>
</ul>
<hr />
<h2 id="heading-2-the-mechanics-of-search-visibility">2. The Mechanics of Search Visibility</h2>
<p>How a user interacts with the <strong>Search Results Page (SERP)</strong> determines your app's success.</p>
<ul>
<li><h3 id="heading-search-suggestions"><strong>Search Suggestions</strong></h3>
<p>  Predictive options are offered by the store as a user types. Optimizing for these "long-tail" suggestions is a key 2026 strategy.</p>
</li>
<li><h3 id="heading-impressions"><strong>Impressions</strong></h3>
<p>  The number of times your app icon is seen in search results or browse lists. An impression is counted when your app appears on a store surface such as search results, charts, or featured placements.</p>
</li>
<li><h3 id="heading-product-page-views-ppv"><strong>Product Page Views (PPV)</strong></h3>
<p>  The count of users who actually clicked your listing to view the full product page (description and screenshots).</p>
</li>
<li><h3 id="heading-apple-search-ads-asa-popularity-score"><strong>Apple Search Ads (ASA) Popularity Score</strong></h3>
<p>  A logarithmic scale (5–100) provided by Apple that indicates the relative popularity of a keyword compared to others in the store. Higher scores indicate relatively higher search popularity compared to other keywords.</p>
</li>
</ul>
<hr />
<h2 id="heading-3-mastering-keyword-strategy">3. Mastering Keyword Strategy</h2>
<p>Keywords are the bridge between user intent and your product. They are specific words and phrases in textual metadata describing the application's function.</p>
<ul>
<li><h3 id="heading-the-semantic-core"><strong>The Semantic Core</strong></h3>
<p>  Your master list of all relevant search phrases that help people find your application.</p>
</li>
<li><h3 id="heading-short-tail-keywords"><strong>Short-tail Keywords</strong></h3>
<p>  Broad, 1-2 word phrases (e.g., "Fitness"). High volume, but extremely high competition.</p>
</li>
<li><h3 id="heading-long-tail-keywords"><strong>Long-tail Keywords</strong></h3>
<p>  Specific, 3+ word phrases (e.g., "Yoga for beginners at home"). Lower volume, but much higher conversion rates due to specific intent.</p>
</li>
<li><h3 id="heading-backlinks"><strong>Backlinks</strong></h3>
<p>  While primary for Web SEO, in Google Play, these external links primarily drive referral traffic and brand discovery, but are not a direct ranking factor.</p>
</li>
</ul>
<hr />
<h2 id="heading-4-user-behavior-and-performance-metrics">4. User Behavior and Performance Metrics</h2>
<p>Once a user finds you, the "ASO work" shifts to conversion and retention.</p>
<ul>
<li><h3 id="heading-conversion-rate-cvr"><strong>Conversion Rate (CVR)</strong></h3>
<p>  In ASO, this specifically refers to <strong>Store Conversion</strong>. CVR measures how many Product Page Views convert into Installs.</p>
</li>
</ul>
<p>$$\text{CVR} = \frac{\text{Total Installs}}{\text{Unique Impressions}}$$</p><ul>
<li><h3 id="heading-install"><strong>Install</strong></h3>
<p>  A successful download completion. Note: An "Install" is tracked by the store even if the user hasn't opened the app yet.</p>
</li>
<li><h3 id="heading-retention-rate"><strong>Retention Rate</strong></h3>
<p>  The percentage of users who return to the app after a specific timeframe (typically measured as <strong>Day 1, Day 7, and Day 30</strong>).</p>
</li>
<li><h3 id="heading-sessions-active-users-daumau"><strong>Sessions / Active Users (DAU/MAU)</strong></h3>
<p>  The industry standard for "Attendance." It measures how many unique users actually open and interact with the app daily or monthly.</p>
</li>
</ul>
<hr />
<h2 id="heading-5-conversion-and-business-strategy">5. Conversion and Business Strategy</h2>
<p>Finally, we look at the metrics that impact the bottom line and the tools used to improve them.</p>
<ul>
<li><h3 id="heading-creative-assets-icon-screenshots-preview-video">Creative Assets (Icon, Screenshots, Preview Video)</h3>
<p>  These are the creative elements that drive conversion. Visual Assets include your <strong>App Icon</strong>, <strong>Screenshots</strong>, and <strong>Preview Video</strong>. They are the primary tools you have to convince a user to install after they have found you via search.</p>
</li>
<li><h3 id="heading-ab-testing"><strong>A/B Testing</strong></h3>
<p>  This is the scientific method of optimization. A/B Testing involves showing two variations of your app store page (e.g., two different icons or screenshot sets) to different segments of users to determine which version results in a higher conversion rate.</p>
</li>
<li><h3 id="heading-user-acquisition-ua-and-cpi"><strong>User Acquisition (UA) and CPI</strong></h3>
<p>  User Acquisition (UA) is the process of acquiring new users on an app or platform. A common model for this is <strong>CPI (Cost Per Install)</strong>, where publishers place digital ads across channels to drive installs.</p>
</li>
<li><h3 id="heading-localization"><strong>Localization</strong></h3>
<p>  To scale globally, you need localization. This is the process of adapting all textual information (description, title, subtitle) from one language to another, taking into account cultural characteristics based on search traffic.</p>
</li>
</ul>
<hr />
<p>Mastering these definitions is the first step toward ASO proficiency. By understanding the difference between short-tail and long-tail keywords, or monitoring your conversion rate and retention alongside install growth, you can move from intuition-based decisions to data-driven growth. This ASO Dictionary: Key Concepts and Vocabulary to be an ASO Expert | ASO Blueprint #2 serves as your foundational guide as you continue to build your expertise.</p>
<p>See you <mark>next </mark> <strong><mark>Sunday</mark></strong> for the next part of the blueprint. We will be diving into the <mark>strategic side of growth:</mark> Where to focus for ASO success&gt; <mark>Brand vs. Generic Keywords.</mark></p>
<h3 id="heading-need-expert-guidance"><strong>Need expert guidance?</strong></h3>
<p>If you need any further review or ASO consultancy, you can contact me directly at <a target="_blank" href="mailto:hello@sajidhasan.com">hello@sajidhasan.com</a></p>
]]></content:encoded></item><item><title><![CDATA[How to Migrate to the SPM-only Google Maps iOS SDK v11 (2026 Guide)]]></title><description><![CDATA[If you manage an iOS project or develop apps using Google Maps, the window for action is rapidly closing. On August 18, 2025, Google officially placed CocoaPods support into maintenance mode. We have now reached the final phase.
By Q2 2026, Google wi...]]></description><link>https://blog.sajidhasan.com/ios-google-maps-v11-spm-migration-guide</link><guid isPermaLink="true">https://blog.sajidhasan.com/ios-google-maps-v11-spm-migration-guide</guid><category><![CDATA[Google Maps iOS SDK v11]]></category><category><![CDATA[SPM migration guide 2026]]></category><category><![CDATA[Google Maps CocoaPods sunset]]></category><category><![CDATA[iOS map migration]]></category><category><![CDATA[Swift Package Manager Google Maps]]></category><category><![CDATA[pod deintegrate google maps]]></category><category><![CDATA[CocoaPods end of life 2026]]></category><category><![CDATA[How to remove CocoaPods from Google Maps iOS]]></category><category><![CDATA[fixing duplicate symbol errors Google Maps SPM]]></category><category><![CDATA[Google Maps SDK v11 maintenance mode]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Wed, 04 Feb 2026 08:06:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770190260539/80f97186-114f-4a75-8447-d363e63f8c29.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you manage an iOS project or develop apps using Google Maps, the window for action is rapidly closing. On August 18, 2025, Google officially placed CocoaPods support into maintenance mode. We have now reached the final phase.</p>
<p>By Q2 2026, Google will stop releasing new versions of the Maps, Places, and Navigation SDKs via CocoaPods entirely. Version 11.0 and all future updates will be exclusive to Swift Package Manager (SPM).</p>
<p>Failing to migrate leaves your app stuck on an outdated SDK, missing new features, performance improvements, and vital security updates. Staying with old dependency managers poses both technical debt and security risks in the fast-paced iOS landscape.</p>
<hr />
<h2 id="heading-what-is-inside-this-guide">What is Inside This Guide</h2>
<ul>
<li><p><strong>Strategic Audit:</strong> Deciding between a full or hybrid migration.</p>
</li>
<li><p><strong>Step by Step Execution:</strong> Stripping legacy files without breaking the build.</p>
</li>
<li><p><strong>Official Sources:</strong> Verified links to Google’s announcements and documentation.</p>
</li>
</ul>
<hr />
<h2 id="heading-1-choose-your-migration-path">1. Choose Your Migration Path</h2>
<p>Depending on your project's complexity, you have two ways to handle this.</p>
<h3 id="heading-option-a-the-full-migration-preferred">Option A: The Full Migration (Preferred)</h3>
<p><strong>Use this if all your dependencies support SPM.</strong> We highly recommend deleting CocoaPods entirely to reduce build overhead and simplify your CI/CD pipeline.</p>
<p><strong>Run these in your terminal:</strong></p>
<pre><code class="lang-bash">sudo gem install cocoapods-deintegrate cocoapods-clean
pod deintegrate
pod cache clean --all
rm Podfile Podfile.lock
rm -rf Pods/
rm -rf YourProject.xcworkspace
</code></pre>
<p><em>From now on, use your</em> <strong><em>.xcodeproj</em></strong> <em>file to manage the project.</em></p>
<h3 id="heading-option-b-the-hybrid-approach">Option B: The ‘Hybrid’ Approach</h3>
<p><strong>Use this if you have legacy pods that do not support SPM yet.</strong> You can keep CocoaPods for those specific libraries while moving Google Maps over to SPM.</p>
<ol>
<li><p><strong>Modify your Podfile:</strong> Delete only the Google Maps related lines (e.g., <code>pod 'GoogleMaps'</code>).</p>
</li>
<li><p><strong>Update your pods:</strong> Run <code>pod install</code> in the terminal. This removes the Google Maps binary while leaving your other pods intact.</p>
</li>
<li><p><strong>Clean Cache:</strong> In Xcode, press <strong>Cmd + Shift + K</strong> to ensure no old headers remain.</p>
</li>
</ol>
<hr />
<h2 id="heading-2-integration-via-swift-package-manager">2. Integration via Swift Package Manager</h2>
<p>Now that the old SDK is removed, follow these steps to link the modern version:</p>
<ol>
<li><p>Open your project in Xcode.</p>
</li>
<li><p>Navigate to <strong>File &gt; Add Package Dependencies</strong>.</p>
</li>
<li><p>Enter the URL: <code>https://github.com/googlemaps/ios-maps-sdk</code>.</p>
</li>
<li><p>Set the <strong>Dependency Rule</strong> to <strong>Up to Next Major Version</strong> (target 11.0.0 for the Q2 release).</p>
</li>
<li><p>Select the specific SDKs your app needs.</p>
</li>
</ol>
<hr />
<h2 id="heading-cocoapods-vs-spm-for-google-maps-sdk-the-2026-breakdown"><strong>CocoaPods</strong> vs. SPM for Google Maps SDK: The 2026 Breakdown</h2>
<p>While CocoaPods served us for years, Google’s shift to SPM is required to unlock <strong>Version 11.0+</strong></p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Feature</strong></td><td><strong>CocoaPods (Legacy)</strong></td><td><strong>Swift Package Manager (2026)</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Max SDK Version</strong></td><td>Stuck at v10.x</td><td><strong>v11.0+ (Latest)</strong></td></tr>
<tr>
<td><strong>OS Support</strong></td><td>Legacy focus</td><td><strong>iOS 26/27/28 Optimized</strong></td></tr>
<tr>
<td><strong>Maintenance</strong></td><td>Ruby/Manual updates</td><td><strong>Native Xcode integration</strong></td></tr>
<tr>
<td><strong>Build Speed</strong></td><td>Slower (Dynamic)</td><td><strong>Faster (Static/Native)</strong></td></tr>
<tr>
<td><strong>Security</strong></td><td>Frozen/Critical Risk</td><td><strong>Active Patching</strong></td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-official-sources-and-documentation">Official Sources and Documentation</h2>
<p>For technical verification and deeper reading, consult these primary sources:</p>
<ul>
<li><p><strong>Google Maps Release Notes:</strong> <a target="_blank" href="https://www.google.com/search?q=https://developers.google.com/maps/documentation/ios-sdk/release-notes%23:~:text%3DAugust%252018%252C%25202025,-Deprecated%26text%3DCocoaPods%2520is%2520in%2520maintenance%2520mode,about%2520using%2520Swift%2520Package%2520Manager.">August 18, 2025 Announcement</a></p>
</li>
<li><p><strong>Official Migration Guide:</strong> <a target="_blank" href="https://developers.google.com/maps/documentation/ios-sdk/versions">Removing CocoaPods Dependencies | Google for Developers</a></p>
</li>
<li><p><strong>Official SPM Repository:</strong> <a target="_blank" href="https://github.com/googlemaps/ios-maps-sdk">Google Maps iOS SDK on GitHub</a></p>
</li>
</ul>
<hr />
<h2 id="heading-need-more-guidance">Need more guidance?</h2>
<p>If your team is facing complex dependency conflicts or needs help refactoring a legacy map implementation, I’m available for technical consultation.</p>
<p><strong>Reach out at:</strong> <a target="_blank" href="mailto:hello@sajidhasan.com">hello@sajidhasan.com</a></p>
]]></content:encoded></item><item><title><![CDATA[Hidden ROI of ASO: Why Organic Growth Beats Paid Acquisition | ASO Blueprint #1]]></title><description><![CDATA[App Store is no longer just a marketplace. It is a crowded digital battlefield. As of early 2026, there are approximately 2.09 million apps on the Apple App Store and roughly 2.18 million on Google Play. With annual downloads projected to reach nearl...]]></description><link>https://blog.sajidhasan.com/aso-blueprint-1-hidden-roi-of-aso</link><guid isPermaLink="true">https://blog.sajidhasan.com/aso-blueprint-1-hidden-roi-of-aso</guid><category><![CDATA[2026 ASO Strategy: Icons, Games & App Tags | ASO Blueprint #1]]></category><category><![CDATA[ASO Blueprint]]></category><category><![CDATA[Organic App Growth]]></category><category><![CDATA[Why organic installs stay longer than paid, App Store search discovery statistics 2026, ASO ROI for Product Managers, scaling iOS apps organically.]]></category><category><![CDATA[App Store Optimization 2026]]></category><category><![CDATA[ASO]]></category><category><![CDATA[App Store Optimization]]></category><category><![CDATA[iOS app marketing]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Sun, 01 Feb 2026 05:28:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769673609892/3863e227-c7e4-4603-97e6-e5849bec5c89.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>App Store is no longer just a marketplace. It is a crowded digital battlefield. As of early 2026, there are approximately 2.09 million apps on the Apple App Store and roughly 2.18 million on Google Play. With annual downloads projected to reach nearly 299 billion globally, the noise is deafening. For Product Managers and Developers, the default reaction is often to increase the ad budget. But there is a more sustainable lever for growth that many overlook: App Store Optimization (ASO).</p>
<h2 id="heading-whats-inside">What’s inside?</h2>
<ul>
<li><p><strong>The 70% Rule</strong>: Why search is the dominant discovery engine in 2026.</p>
</li>
<li><p><strong>The Intent Gap</strong>: Why organic users stay 150% longer than paid ones.</p>
</li>
<li><p><strong>Strategy Shift</strong>: When to focus on Brand vs. Generic search.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769671852051/4505bcb9-c33e-4612-b78c-f5986dd898b6.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://42matters.com/stats">Statistical Data Source: 42matters - App Store Statistics</a> <em>(accessed: 29 January 2026)</em></p>
<hr />
<h2 id="heading-the-seo-of-the-mobile-world">The SEO of the Mobile World</h2>
<p>At its core, ASO is simply SEO for app stores. It is a process designed to do one thing: maximize visibility and conversion rates.</p>
<p>While paid user acquisition stops working the moment you stop paying, ASO is an investment in your app organic foundation. It is the most cost efficient way to acquire users because success depends totally on your effort, not just your budget.</p>
<h2 id="heading-the-70-rule-why-search-dominates">The 70% Rule: Why Search Dominates</h2>
<p>If you think most users find apps through social media ads, look at the latest data. According to official Apple Search Ads insights for 2026, 70% of App Store visitors use search to discover apps. Even more telling, 65% of all downloads happen directly after a search.</p>
<p>This means the vast majority of your potential audience is actively looking for a solution. If your app is not optimized to appear in those search results, you are invisible to nearly three quarters of the market.</p>
<h2 id="heading-the-intent-gap-quality-over-quantity">The Intent Gap: Quality Over Quantity</h2>
<p>Not all installs are created equal. One of the most critical metrics for any product manager is the Retention Rate.</p>
<p>Recent data reveals a striking difference: customers acquired through search have a 150% higher retention rate than users acquired through paid campaigns. Organic users discover your app because they have intent. They were searching for a specific solution, found your app, and chose it. This makes them more loyal and more likely to monetize over time compared to paid users who may have been interrupted by an ad.</p>
<h2 id="heading-context-matters-brand-vs-generic-keywords">Context Matters: Brand vs. Generic Keywords</h2>
<p>Your ASO strategy depends entirely on your product type.</p>
<ul>
<li><h3 id="heading-the-brand-challenge">The Brand Challenge:</h3>
<p>  If you launch a new messenger app, you will struggle with generic search traffic because most users search for specific names like Facebook, Snapchat, or Viber.</p>
</li>
<li><h3 id="heading-the-generic-opportunity">The Generic Opportunity:</h3>
<p>  If you have a News, Music, or Dating app, you have massive potential to gain installs from generic keywords like dating app or music player.</p>
</li>
</ul>
<p>We will have a dedicated, detailed Brand vs. Generic Keywords deep dive blog in a future ASO Blueprint to help you master this.</p>
<hr />
<p>ASO is not just a marketing task. It is the backbone of your growth strategy. Whether you are an indie developer or leading a product team, optimizing your metadata and visuals is a must have to reach relevant users and drive sustainable downloads.</p>
<p>See you <strong><mark>next Sunday</mark></strong> for the next part of the blueprint. We will deep dive into the <strong><mark>ASO Dictionary (key concepts and vocabulary we must know to be an ASO expert)</mark></strong>.</p>
]]></content:encoded></item><item><title><![CDATA[iOS Notification Types: A Strategy Guide for User Engagement]]></title><description><![CDATA[Choosing the correct notification architecture is a critical decision in modern mobile product strategy. Whether you are optimizing for user retention or minimizing churn, understanding the nuances between local, remote, and silent triggers is essent...]]></description><link>https://blog.sajidhasan.com/ios-notification-types-engagement-strategy</link><guid isPermaLink="true">https://blog.sajidhasan.com/ios-notification-types-engagement-strategy</guid><category><![CDATA[iOS notification]]></category><category><![CDATA[Push vs Local notifications]]></category><category><![CDATA[iOS background sync]]></category><category><![CDATA[Rich push engagement]]></category><category><![CDATA[ app notification strategy]]></category><category><![CDATA[iOS]]></category><category><![CDATA[ios app development]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Sun, 25 Jan 2026 06:24:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769185708215/237e07dd-0f0e-43f6-90f1-0ea6a2ab06f3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Choosing the correct notification architecture is a critical decision in modern mobile product strategy. Whether you are optimizing for user retention or minimizing churn, understanding the nuances between local, remote, and silent triggers is essential for any high-performance iOS application.</p>
<p><strong>What’s inside?</strong></p>
<p>This guide explores the <strong>5 primary iOS notification architectures, comparing their technical triggers with high-level UX strategies</strong> to help you choose the right communication tool for your users.</p>
<h2 id="heading-quick-strategy-comparison-technical-choice-vs-business-value">Quick Strategy Comparison: Technical Choice vs. Business Value</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Notification Type</strong></td><td><strong>Trigger Source</strong></td><td><strong>UX Strategy</strong></td><td><strong>Business ROI</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Local</strong></td><td>On-Device</td><td>Offline Utility</td><td>User Retention</td></tr>
<tr>
<td><strong>Remote (Push)</strong></td><td>Server (APNs)</td><td>Real-Time Info</td><td>Active Engagement</td></tr>
<tr>
<td><strong>Silent</strong></td><td>Server (APNs)</td><td>Background Sync</td><td>Seamless Performance</td></tr>
<tr>
<td><strong>In-App</strong></td><td>NotificationCenter</td><td>Active Session</td><td>Feature Discovery</td></tr>
<tr>
<td><strong>Rich Push</strong></td><td>Service Extension</td><td>High Engagement</td><td>Conversion Rate</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-1-local-notifications-optimizing-for-offline-reliability">1. Local Notifications: Optimizing for Offline Reliability</h2>
<p><strong>Best for:</strong> Personalized reminders and time-sensitive tasks without server dependency.</p>
<p>Local notifications are triggered by the device's internal clock. From a <strong>UX perspective</strong>, they are the most reliable way to provide value without requiring an internet connection.</p>
<ul>
<li><p><strong>Key Use Cases:</strong> Medication trackers, daily habit reminders, and "Drink Water" alerts.</p>
</li>
<li><p><strong>Permission Requirement:</strong> Requires explicit <code>UNUserNotificationCenter</code> authorization.</p>
</li>
<li><p><strong>Example:</strong> <em>“Don’t forget your 9 AM hydration goal!”</em></p>
</li>
</ul>
<h2 id="heading-2-remote-push-notifications-driving-real-time-user-action">2. Remote (Push) Notifications: Driving Real-Time User Action</h2>
<p><strong>Best for:</strong> Connecting the user to external events and dynamic updates.</p>
<p>Sent via <strong>Apple Push Notification service (APNs)</strong>, these are the gold standard for re-engaging users.</p>
<ul>
<li><p><strong>Key Use Cases:</strong> Chat messaging, e-commerce order tracking, and breaking news.</p>
</li>
<li><p><strong>GEO Strategy:</strong> Ensure payloads are concise; high-relevance alerts reduce the likelihood of "Notification Muting."</p>
</li>
<li><p><strong>Example:</strong> <em>“Your order has been shipped and is on its way!”</em></p>
</li>
</ul>
<h2 id="heading-3-silent-notifications-the-secret-to-seamless-data-synchronization">3. Silent Notifications: The Secret to Seamless Data Synchronization</h2>
<p><strong>Best for:</strong> Background updates that prevent "Pull-to-Refresh" latency.</p>
<p>Silent notifications (using <code>content-available: 1</code>) request a background wake to download data without alerting the user.</p>
<ul>
<li><p><strong>UX Win:</strong> By the time the user opens the app, the content is already fresh. This creates a "premium" feel by eliminating loading spinners.</p>
</li>
<li><p><strong>Note:</strong> iOS uses <strong>intelligent throttling</strong> to protect battery life, so these should be used for non-critical data sync.</p>
</li>
</ul>
<h2 id="heading-4-rich-push-notifications-increasing-conversion-with-interactivity">4. Rich Push Notifications: Increasing Conversion with Interactivity</h2>
<p><strong>Best for:</strong> Deep engagement and secure communication.</p>
<p>Rich notifications use <strong>Service Extensions</strong> to add images, GIFs, and action buttons.</p>
<ul>
<li><p><strong>Strategic Advantage:</strong> They allow users to complete tasks (like replying to a message or approving a request) without leaving the Lock Screen.</p>
</li>
<li><p><strong>Security Feature:</strong> A key tool for End-to-End Encryption, as they allow for on-device decryption of sensitive data.</p>
</li>
</ul>
<h2 id="heading-5-custom-in-app-notifications-enhancing-the-active-user-experience">5. Custom In-App Notifications: Enhancing the Active User Experience</h2>
<p><strong>Best for:</strong> Real-time feedback while the app is in the foreground.</p>
<p>Using NotificationCenter for internal broadcasting, these alerts guide the user through their current journey without cluttering the system-wide Notification Center.</p>
<ul>
<li><strong>Example:</strong> <em>“Settings saved successfully”</em></li>
</ul>
<hr />
<h2 id="heading-critical-alerts-the-exception-for-urgent-communication">Critical Alerts: The Exception for Urgent Communication</h2>
<p>For apps in <strong>Health, Security, or Emergency services</strong>, Critical Alerts can bypass "Do Not Disturb" and the "Mute" switch. This is a high-trust entitlement from Apple used to ensure life-critical information is never missed.</p>
<h2 id="heading-strategy-guide-how-to-maximize-engagement-without-notification-fatigue">Strategy Guide: How to Maximize Engagement Without "Notification Fatigue"</h2>
<p>To ensure your notification strategy scales, follow these <strong>UX Best Practices</strong>:</p>
<ol>
<li><p><strong>Contextual Awareness:</strong> Don't send a Push if the user is in the app; use an <strong>In-App</strong> alert instead.</p>
</li>
<li><p><strong>Reduce Friction:</strong> Use <strong>Rich Notifications</strong> so users can interact instantly.</p>
</li>
<li><p><strong>Prioritize Privacy:</strong> Use <strong>Silent Notifications</strong> for background work to keep the UI clean.</p>
</li>
<li><p><strong>Value-First Approach:</strong> If an alert doesn't help the user, it’s spam. Every notification should provide a "Next Step."</p>
</li>
</ol>
<p>In 2026, the difference between a high-retention app and one that gets deleted is <strong>context</strong>. By leveraging the right mix of Silent syncs and Rich interactivity, you transform your app from an interruption into an indispensable tool.</p>
]]></content:encoded></item><item><title><![CDATA[The Password Eye Dilemma -What’s the Right UX?]]></title><description><![CDATA[You’re working on a login screen. You’ve got the email field. You’ve got the password field. You add a simple "eye" icon to toggle visibility.
…and then the brain hits pause:

🤔
What icon should I show beside the password field?



Should it be an o...]]></description><link>https://blog.sajidhasan.com/password-eye-dilemma</link><guid isPermaLink="true">https://blog.sajidhasan.com/password-eye-dilemma</guid><category><![CDATA[password eye]]></category><category><![CDATA[UX]]></category><category><![CDATA[app development]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[iOS]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[UI]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Wed, 30 Jul 2025 10:28:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753862939971/93ee08db-7f72-4f1f-9b82-8bceedd7a4d4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You’re working on a login screen. You’ve got the email field. You’ve got the password field. You add a simple "eye" icon to toggle visibility.</p>
<p>…and then the brain hits pause:</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">🤔</div>
<div data-node-type="callout-text"><strong>What icon should I show beside the password field?</strong></div>
</div>

<ul>
<li><p>Should it be an open eye when the password is hidden?</p>
</li>
<li><p>Should it be a closed eye when the password is hidden?</p>
</li>
<li><p>What happens after the user taps?</p>
</li>
</ul>
<p>Let’s unpack this tiny but surprisingly common UX debate.</p>
<h2 id="heading-two-common-approaches">Two Common Approaches</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753864989784/17c982ed-6403-40ca-997e-aa2b5e7e61b8.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-option-1-open-eye-tap-to-reveal-password">Option 1: Open Eye = Tap to reveal password</h3>
<ul>
<li><p><strong>Eye icon (👁️)</strong> = Password is hidden → tapping it reveals password</p>
</li>
<li><p><strong>Eye-slash icon (🙈)</strong> = Password is visible → tapping it hides password</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">This approach is more <strong>instructional</strong>. The icon indicates what will happen if you tap it: a “show password” or “hide password” toggle.</div>
</div>

<p><strong>Pros:</strong> Suggests the action.<br /><strong>Cons:</strong> Technically shows the opposite of the current state.</p>
<h3 id="heading-option-2-open-eye-youre-seeing-the-password">Option 2: Open Eye = You’re seeing the password</h3>
<ul>
<li><p><strong>Eye icon (👁️)</strong> = Password is visible</p>
</li>
<li><p><strong>Eye-slash icon (🙈)</strong> = Password is hidden</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">This is more <strong>descriptive</strong>. The icon represents the current state of the password field.</div>
</div>

<p><strong>Pros:</strong> Matches the meaning of the icon.<br /><strong>Cons:</strong> May confuse users who assume the icon is a button to reveal the password.</p>
<h2 id="heading-alternatives-to-consider">Alternatives to Consider</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753865656423/68a753a5-e9ee-4b5b-83cf-f77bf5442d01.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Use text: <code>"Show"</code> / <code>"Hide"</code> — like LinkedIn</p>
</li>
<li><p>Use a checkbox with a label (☐ Show password) — like Google</p>
</li>
<li><p>Use a toggle switch (less common but clearer)</p>
</li>
<li><p>Skip the toggle if you're using Apple’s secure autofill</p>
</li>
</ul>
<h2 id="heading-what-do-the-giants-do">What Do the Giants Do?</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753865894475/d495fa1e-f0fe-46a7-ae06-8e240a757146.png" alt class="image--center mx-auto" /></p>
<p><em>\</em>Checked on July 30, 2025.*</p>
<p><strong>Google</strong></p>
<ul>
<li><p>Uses a <strong>checkbox</strong> labeled <code>Show password</code> under the input field</p>
</li>
<li><p>No icon, no visual toggle. Just plain and accessible.</p>
</li>
</ul>
<p><strong>LinkedIn</strong></p>
<ul>
<li><p>Uses a <strong>text toggle button</strong> that says <code>Show</code> or <code>Hide</code></p>
</li>
<li><p>Appears inside the password field on the right side</p>
</li>
</ul>
<p><strong>Facebook</strong></p>
<ul>
<li><p>Uses the <code>Open Eye = You’re seeing the password</code> approach</p>
</li>
<li><p>No label or text, just the visual indicator</p>
</li>
</ul>
<p><strong>Apple &amp; Microsoft</strong></p>
<ul>
<li><p>Do <strong>not</strong> use any visibility toggle at all</p>
</li>
<li><p>Prioritize security and assume passwords are masked for a reason</p>
</li>
</ul>
<h2 id="heading-so-whats-the-standard">So... What’s the Standard?</h2>
<p><strong>Short answer:</strong> Both are technically acceptable.</p>
<p><strong>Long answer:</strong> It depends on the UX logic you want to prioritize.</p>
<p>There’s no official Apple Human Interface Guidelines or Material Design guideline that mandates either approach, which is why different teams do different things.</p>
<p>However, the most intuitive and commonly accepted UX today is:</p>
<ul>
<li><p>Default: Crossed eye (password is hidden)</p>
</li>
<li><p>Tapping shows password → icon switches to open eye</p>
</li>
<li><p>Optional: <strong>Add a tooltip or accessibility label for extra clarity</strong></p>
</li>
</ul>
<p>There’s no absolute “standard,” but consistency and clarity should always win.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">If your user base is broad (or less tech-savvy), lean toward the checkbox or text toggle. If you're designing for power users or mobile-first apps, the eye icon works well. Just make sure its meaning is clear.</div>
</div>]]></content:encoded></item><item><title><![CDATA[Top 5 iOS Interview Questions – And How to Answer Them]]></title><description><![CDATA[In this guide, we will explore the five most common iOS interview questions, focusing not only on what to say but also on how to approach them in a way that resonates with interviewers.
1. Optionals in Swift

💡
Answer Like You Use Them Every Day


I...]]></description><link>https://blog.sajidhasan.com/top-5-ios-interview-questions</link><guid isPermaLink="true">https://blog.sajidhasan.com/top-5-ios-interview-questions</guid><category><![CDATA[iOS]]></category><category><![CDATA[ios app development]]></category><category><![CDATA[interview]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[interview questions]]></category><category><![CDATA[Interview tips]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Thu, 24 Jul 2025 08:42:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753251320501/a975f4cf-d427-4ca9-ae0e-d6b347b761c4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this guide, we will explore the five most common iOS interview questions, focusing not only on what to say but also on how to approach them in a way that resonates with interviewers.</p>
<h2 id="heading-1-optionals-in-swift">1. Optionals in Swift</h2>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Answer Like You Use Them Every Day</div>
</div>

<p>Interviewers often start here to test your Swift fundamentals. You’re expected to know what optionals are, but your job is to show you understand why Swift has them and how to use them safely.</p>
<h3 id="heading-your-approach">Your Approach:</h3>
<ul>
<li><p><strong>Start with the concept</strong>: An ‘optional’ is a type that can hold a value or be nil.</p>
</li>
<li><p><strong>Mention the real-world use case</strong>: Any situation where a value may or may not exist. For example: API response, user input, etc.</p>
</li>
<li><p><strong>Explain unwrapping techniques</strong>:</p>
<ul>
<li><p><strong>Optional Binding (</strong><code>if let</code>, <code>guard let</code>): The preferred and safest methods.</p>
</li>
<li><p><strong>Optional Chaining</strong>: For safely accessing properties or calling methods on an optional.</p>
</li>
<li><p><strong>Nil-Coalescing Operator (</strong><code>??</code>): Providing a default value if the optional is <code>nil</code>.</p>
</li>
<li><p><em>(Briefly mention</em> <strong><em>force unwrapping</em></strong> <em>(</em><code>!</code>) as something to largely avoid in production code, highlighting its dangers.)</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-2-struct-vs-class">2. Struct vs Class</h2>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Don’t Just List Differences, Tell When to Use What</div>
</div>

<p>This is a chance to demonstrate your understanding of Swift’s type system and memory model.</p>
<h3 id="heading-your-approach-1">Your Approach:</h3>
<ul>
<li><p><strong>Set the stage</strong>:</p>
<ul>
<li><p>Structs are <strong>value</strong> types (copied when passed or assigned).</p>
</li>
<li><p>Classes are <strong>reference</strong> types (passed by reference, meaning multiple variables can point to the same instance).</p>
</li>
</ul>
</li>
<li><p><strong>Mention storage</strong>:</p>
<ul>
<li><p>Structs are typically stored on the <strong>stack</strong> (for performance and simplicity)</p>
</li>
<li><p>Classes stored on the <strong>heap</strong> (allowing for shared instances and more complex object graphs)</p>
</li>
</ul>
</li>
<li><p><strong>Examples</strong>: Provide simple, clear examples of when you would choose a struct (e.g., small data models, thread safety) versus a class (e.g., shared mutable state, inheritance).</p>
</li>
<li><p><strong>Key Features</strong>: Discuss features like inheritance (classes only), deinitializers (classes only), and mutability behavior.</p>
</li>
</ul>
<h3 id="heading-goal">Goal:</h3>
<p>You’re not just showing that you <em>know</em> Swift. You’re showing that you make thoughtful architecture choices.</p>
<h2 id="heading-3-memory-management-in-swift">3. Memory Management in Swift</h2>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Show You Can Spot and Avoid Leaks</div>
</div>

<p>Every iOS app deals with memory. Interviewers want to see if you can keep your app healthy and performant.</p>
<h3 id="heading-your-approach-2">Your Approach:</h3>
<ul>
<li><p><strong>Start with ARC</strong>: Swift uses <em>Automatic Reference Counting</em> to manage memory.</p>
</li>
<li><p><strong>Define how it works</strong>: Explain how ARC automatically manages memory by tracking strong references to instances. Each object has a reference count. When it drops to 0, it's deallocated.</p>
</li>
<li><p>Talk about <strong>Strong vs Weak vs Unowned</strong> references:</p>
<ul>
<li><p><strong>Strong</strong>: The default, <strong>increments</strong> the reference count.</p>
</li>
<li><p><strong>Weak</strong>: Does <strong>not increment</strong> the reference count. Used to break retain cycles when the other object has a shorter or equal lifetime (e.g., delegates). <code>weak</code> references are automatically set to <code>nil</code> when the object they point to is deallocated.</p>
</li>
<li><p><strong>Unowned</strong>: Does <strong>not increment</strong> the reference count. Used when you're sure the other object will have the same or longer lifetime (e.g., capturing <code>self</code> in closures when <code>self</code> is guaranteed to exist). <code>unowned</code> references are not optional and are assumed to always have a value.</p>
</li>
</ul>
</li>
<li><p><strong>Bring up retain cycles</strong>: especially in closures or between two objects that hold strong references to each other.</p>
</li>
<li><p><strong>Connect back to practice</strong>: Use <code>[weak self]</code> in closures, especially in view controllers and async tasks.</p>
</li>
</ul>
<h3 id="heading-goal-1">Goal:</h3>
<p>Make the interviewer feel confident that their code is in good hands.</p>
<h2 id="heading-4-app-architecture">4. App Architecture</h2>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Show that you pick the pattern based on the context, not because it's trendy.</div>
</div>

<p>You’ll likely get a question about how you structure your codebase. This is your chance to show that you think about <strong>scalability and maintainability.</strong></p>
<h3 id="heading-your-approach-3">Your Approach:</h3>
<ul>
<li><p><strong>Acknowledge MVC (Model-View-Controller)</strong>: Talk about its simplicity, and also its limitations (especially the "<em>Massive View Controller</em>" problem).</p>
</li>
<li><p><strong>Introduce MVVM (Model-View-ViewModel)</strong>:</p>
<ul>
<li><p>ViewModel separates logic from the ViewController</p>
</li>
<li><p>Easier to test, reuse, and reason about</p>
</li>
<li><p>Works well with Combine or SwiftUI</p>
</li>
</ul>
</li>
<li><p><strong>Mention VIPER (View-Interactor-Presenter-Entity-Router) if relevant</strong>:</p>
<ul>
<li><p>A more opinionated and rigid architecture, offering clearer separation of concerns</p>
</li>
<li><p>Use in large teams or modular projects</p>
</li>
</ul>
</li>
<li><p><strong>Why a Specific Architecture?</strong>: Be prepared to discuss the pros and cons of your chosen architecture and why it's suitable for different project sizes or complexities.</p>
</li>
</ul>
<h2 id="heading-5-building-a-feature">5. Building a Feature</h2>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">This is Where You Think Out Loud</div>
</div>

<p>This is usually an open-ended question like “How would you build a chat screen?” It tests how you think, design, and communicate.</p>
<h3 id="heading-your-approach-4">Your Approach:</h3>
<ul>
<li><p><strong>Step 1: Understand the requirement</strong></p>
<ul>
<li>Don't jump straight to coding. Take a moment to understand the requirements fully. Ask clarifying questions about scope, constraints, and dependencies.</li>
</ul>
</li>
<li><p><strong>Step 2: Break down the components</strong></p>
<ul>
<li><p>UI: views, controllers, SwiftUI or UIKit</p>
</li>
<li><p>Data: models, persistence, networking</p>
</li>
<li><p>Logic: ViewModel, managers, business logic</p>
</li>
</ul>
</li>
<li><p><strong>Step 3: Pick an architecture</strong></p>
<ul>
<li><p>MVC for simple</p>
</li>
<li><p>MVVM or VIPER for more structured needs</p>
</li>
</ul>
</li>
<li><p><strong>Step 4: Mention tools and techniques</strong></p>
<ul>
<li><p>URLSession or Alamofire?</p>
</li>
<li><p>Local storage with Core Data or Realm?</p>
</li>
</ul>
</li>
<li><p><strong>Step 5: Think of the user</strong></p>
<ul>
<li><p>Error handling</p>
</li>
<li><p>Loading states</p>
</li>
<li><p>Empty states</p>
</li>
</ul>
</li>
<li><p><strong>Step 6: Talk about testing</strong></p>
<ul>
<li><p>Unit testing the ViewModel</p>
</li>
<li><p>UI tests for flow</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-goal-2">Goal:</h3>
<p>You are not just solving a problem. You are architecting a thoughtful, reusable, and user friendly solution.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Interviewers don’t just want the right answer. They want to see how you think. That’s why the best prep isn’t memorizing terms, but learning how to explain the <em>why</em> behind every decision you make.</p>
<p>By mastering these key areas, from fundamental Swift types and memory management to advanced architectural patterns and practical feature implementation, you'll be well on your way to acing your next iOS development interview.</p>
<p>Understand the core concepts. Practice explaining them simply. And always tie your answers back to real world usage. That’s how you stand out. Good luck!</p>
<hr />
<p>Get prepared with my full iOS Interview Guide Blog Series:</p>
<p><a target="_blank" href="https://blog.sajidhasan.com/series/ios-interview">https://blog.sajidhasan.com/series/ios-interview</a></p>
<p><a target="_blank" href="https://blog.sajidhasan.com/series/ios-interview"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720544075449/11f6619d-d3e8-42d9-b5ae-bc869d5f07fe.jpeg" alt="iOS Interview Series by Sajid" class="image--center mx-auto" /></a></p>
<p>iOS Interview Series covers essential topics for mastering iOS development interviews, from Swift basics to advanced concepts.</p>
]]></content:encoded></item><item><title><![CDATA[Write Swift Booleans Like a Pro: Clean Code Guide]]></title><description><![CDATA[Ever stared at your code and thought, “Who wrote this mess?” ...and it was you? We've all been there.
Clean code isn’t just about satisfying the compiler. It’s about writing something your future self and your team won’t dread revisiting. One easy wi...]]></description><link>https://blog.sajidhasan.com/write-swift-booleans-like-a-pro</link><guid isPermaLink="true">https://blog.sajidhasan.com/write-swift-booleans-like-a-pro</guid><category><![CDATA[Swift]]></category><category><![CDATA[Boolean]]></category><category><![CDATA[clean code]]></category><category><![CDATA[iOS]]></category><category><![CDATA[ios app development]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Thu, 17 Apr 2025 07:09:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744872462571/31a99001-498a-4f8b-b7de-ffa7724040f0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ever stared at your code and thought, “Who wrote this mess?” ...and it was you? We've all been there.</p>
<p>Clean code isn’t just about satisfying the compiler. It’s about writing something your future self and your team won’t dread revisiting. One easy win? Start by naming your boolean variables right.</p>
<p>This blog focuses on Swift, but these naming principles apply to any language.</p>
<p>As iOS developers, we spend a lot of time dealing with logic and states. Yet sometimes, our code reads more like cryptic commands than understandable sentences.</p>
<p>Like Steve Jobs once said:</p>
<blockquote>
<p>“Simple can be harder than complex. You have to <strong>work hard to get your thinking clean to make it simple</strong>.”</p>
</blockquote>
<p>So let’s simplify and make our code cleaner by prefixing booleans like we mean it.</p>
<hr />
<h2 id="heading-the-boolean-naming-cheatsheet">The Boolean Naming Cheatsheet</h2>
<p>Here’s a quick rulebook I follow and it works not just for Swift, but pretty much any language:</p>
<hr />
<h3 id="heading-is-for-states"><code>is</code> — For states</h3>
<p>Use <code>is</code> when you're expressing the current state of something.</p>
<p><strong>Bad:</strong></p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> active { ... }
</code></pre>
<p><strong>Good:</strong></p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> isActive { ... }
</code></pre>
<p>Now it reads like English. Is active?</p>
<hr />
<h3 id="heading-has-for-ownership-or-possession"><code>has</code> — For ownership or possession</h3>
<p>Use <code>has</code> when referring to something your object holds or owns.</p>
<p><strong>Bad:</strong></p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> subscription { ... }
</code></pre>
<p><strong>Good:</strong></p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> hasSubscription { ... }
</code></pre>
<p>Does it have a subscription?</p>
<hr />
<h3 id="heading-should-for-expectations-or-conditions"><code>should</code> — For expectations or conditions</h3>
<p>Use <code>should</code> to indicate what <em>ought to</em> happen next.</p>
<p><strong>Bad:</strong></p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> retry { ... }
</code></pre>
<p><strong>Good:</strong></p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> shouldRetry { ... }
</code></pre>
<p>We’re no longer wondering if "retry" is a flag, a method, or a mood. It’s an expectation, and it tells us clearly what to do.</p>
<hr />
<h3 id="heading-can-for-capabilities"><code>can</code> — For capabilities</h3>
<p>Use <code>can</code> when referring to permissions or abilities.</p>
<p><strong>Bad:</strong></p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> edit { ... }
</code></pre>
<p><strong>Good:</strong></p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> canEdit { ... }
</code></pre>
<p>It’s not just about editing, it’s about whether the user <em>can</em> edit. Huge difference in clarity.</p>
<hr />
<h2 id="heading-now-read-it-like-english">Now read it like English</h2>
<p>A good rule of thumb: your <code>if</code> statements should read like a sentence:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> user.canEdit &amp;&amp; user.hasSubscription &amp;&amp; !user.isBlocked {
    showEditor()
}
</code></pre>
<p>Clean, understandable, and super readable, even for someone new to the codebase.</p>
<hr />
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Writing clean code is a habit, not a plugin. These boolean prefixes may seem small, but they can dramatically improve the readability and maintainability of your code, especially when working in teams or revisiting old projects.</p>
<p>Swift is beautiful. Let’s write like it.</p>
]]></content:encoded></item><item><title><![CDATA[iOS and Android Apps with Swift using Skip: Step-by-Step Guide]]></title><description><![CDATA[Let's start with a dream of an iOS developer: a Swift codebase in Xcode that can run on both iOS and Android just like a native app! With Skip.tools, this dream is now a reality. Although still in its early stages, I hope more open-source solutions l...]]></description><link>https://blog.sajidhasan.com/ios-and-android-apps-with-swift-using-skip-step-by-step-guide</link><guid isPermaLink="true">https://blog.sajidhasan.com/ios-and-android-apps-with-swift-using-skip-step-by-step-guide</guid><category><![CDATA[Skip tools]]></category><category><![CDATA[iOS]]></category><category><![CDATA[Android]]></category><category><![CDATA[Cross Platform App Development. ]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[app development]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Tue, 18 Feb 2025 15:39:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739891004414/3752e529-2407-4427-acaa-df6c4d4c3406.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let's start with a dream of an iOS developer: a Swift codebase in Xcode that can run on both iOS and Android just like a native app! With <a target="_blank" href="http://Skip.tools">Skip.tools</a>, this dream is now a reality. Although still in its early stages, I hope more open-source solutions like this will make the dream come true!</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">You can find an example implementation here: <a target="_blank" href="https://github.com/SajidHShanta/Skip-Swift-app-to-Android">https://github.com/SajidHShanta/Skip-Swift-app-to-Android</a></div>
</div>

<h2 id="heading-getting-started-with-skip">Getting Started with Skip</h2>
<h3 id="heading-1-prerequisites">1. Prerequisites</h3>
<p>Ensure you have the following installed on your macOS system:</p>
<ul>
<li><p><strong>Xcode</strong> (for iOS development)</p>
</li>
<li><p><strong>Android Studio</strong> (for Android emulator)</p>
</li>
<li><p><strong>Homebrew</strong> (for package management)</p>
</li>
</ul>
<p>If Homebrew is not installed, you can install it from here: <a target="_blank" href="https://docs.brew.sh/Installation">https://docs.brew.sh/Installation</a></p>
<h3 id="heading-2-install-skip">2. Install Skip</h3>
<p>To install Skip, run the following command in your terminal:</p>
<pre><code class="lang-swift">brew install skiptools/skip/skip
</code></pre>
<p>Once installed, verify the setup with:</p>
<pre><code class="lang-swift">skip checkup
</code></pre>
<p>This command checks for missing dependencies and ensures everything is ready.</p>
<h3 id="heading-3-create-a-dual-platform-app">3. Create a Dual-Platform App</h3>
<p>To initialize a new Skip project, use the following command:</p>
<pre><code class="lang-swift">skip <span class="hljs-keyword">init</span> --appid=bundle.id project-name <span class="hljs-type">AppName</span>
</code></pre>
<ul>
<li><p><strong>bundle id</strong>: Your app's unique identifier (e.g., <code>com.example.myapp</code>)</p>
</li>
<li><p><strong>project-name</strong>: The folder where your project will be created.</p>
</li>
<li><p><strong>AppName</strong>: The display name of your app.</p>
</li>
</ul>
<h3 id="heading-example-command">Example Command:</h3>
<pre><code class="lang-swift">skip <span class="hljs-keyword">init</span> --<span class="hljs-keyword">open</span>-xcode --appid=com.sajidhasan.testskip test-skip <span class="hljs-type">TestSkip</span>
</code></pre>
<p><code>--open-xcode</code> flag automatically opens the project in Xcode after initialization.</p>
<h3 id="heading-4-preparing-the-android-emulator">4. Preparing the Android Emulator</h3>
<p>The <code>skip init</code> command generates a working template, but before building and running the app, you need to have an Android emulator up and running.</p>
<ol>
<li><p>Open <strong>Android Studio.app</strong>.</p>
</li>
<li><p>Go to <strong>Virtual Device Manager</strong> (from the ellipsis menu on the Welcome screen).</p>
</li>
<li><p>Click <strong>Create Device</strong> and follow the steps to set up a virtual Android device.</p>
</li>
<li><p>Once created, <strong>Launch</strong> the emulator.</p>
</li>
</ol>
<p>Ensure the emulator is running before building your app.</p>
<h3 id="heading-5-explore-and-build">5. Explore and Build</h3>
<p>Once your project is set up:</p>
<ol>
<li><p>Open the Xcode workspace if it is not already open.</p>
</li>
<li><p>Write your Swift code as usual.</p>
</li>
<li><p>Use Xcode to build and run the app on both iOS and Android simulators.</p>
</li>
</ol>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>And that’s it. You are now equipped with Skip. Explore more functionalities from the <a target="_blank" href="https://skip.tools/docs/gettingstarted/">Skip documentation</a> and discover what you can achieve with this tool. Happy coding!</p>
<p>I would love to connect with you on LinkedIn. Here’s my profile: <a target="_blank" href="https://www.linkedin.com/in/sajidshanta/"><strong>https://www.linkedin.com/in/sajidshanta/</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[AI Avatar with Apple Intelligence -SwiftUI Image Playground]]></title><description><![CDATA[Apple introduces a great app, Image Playground. We can make images from scratch or from existing ones with our prompts, and we can also use this in our own apps. For example, we can elevate our apps with an AI Avatar creation feature for users with s...]]></description><link>https://blog.sajidhasan.com/ai-avatar-with-apple-intelligence-swiftui-image-playground</link><guid isPermaLink="true">https://blog.sajidhasan.com/ai-avatar-with-apple-intelligence-swiftui-image-playground</guid><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Mon, 10 Feb 2025 05:42:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739164960157/ce91fcbc-0601-41ec-ac97-c959108dd4ef.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Apple introduces a great app, Image Playground. We can make images from scratch or from existing ones with our prompts, and we can also use this in our own apps. For example, we can elevate our apps with an AI Avatar creation feature for users with some simple code of Image Playground.</p>
<p>Before starting, ensure you have the required setup for Apple Intelligence: iOS 18.1 or later, iPadOS 18.1 or later, and macOS 15.1 or later. Now, Create a new SwiftUI project, and let’s get started.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739165565731/7699d6c4-87af-4f15-9380-fbea34209091.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://github.com/SajidHShanta/exploring-repo/blob/main/AIAvatar/AIAvatar/ContentView.swift"><mark>Get the complete code from GitHub(click here)</mark></a> and follow the steps below to understand the implementation.</p>
<p>First, Import <code>ImagePlayground</code> and <code>PhotosUI</code> in <code>ContentView.swift</code> just after importing SwiftUI.</p>
<p>Next, create five variables:</p>
<ol>
<li><p>An environment variable <code>supportsImagePlayground</code> to check if the device supports Image Playground.</p>
</li>
<li><p>An empty string <code>imageGenerationConcept</code>, will represent the user's prompt.</p>
</li>
<li><p>A Boolean variable to determine whether Image Playground is currently displayed.</p>
</li>
<li><p>An optional variable for an avatar image.</p>
</li>
<li><p>A variable for a photo picker item.</p>
</li>
</ol>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> SwiftUI
<span class="hljs-keyword">import</span> ImagePlayground
<span class="hljs-keyword">import</span> PhotosUI


<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{

    @<span class="hljs-type">Environment</span>(\.supportsImagePlayground) <span class="hljs-keyword">var</span> supportsImagePlayground
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> imageGenerationCooncept = <span class="hljs-string">""</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> isShowingImagePlayground = <span class="hljs-literal">false</span>

    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> avatarImage: <span class="hljs-type">Image?</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> photosPickerItem: <span class="hljs-type">PhotosPickerItem?</span>
</code></pre>
<hr />
<p>Now, build a <strong>profile UI</strong>, which includes a <strong>photo picker</strong> for selecting a profile picture, a <strong>name</strong> and <strong>title section</strong>, and a <strong>text field</strong> where users can enter a <strong>prompt</strong> for AI-generated avatars <em>(if Image Playground is supported)</em>. A <strong>button</strong> allows users to trigger AI image generation, and the generated avatar updates dynamically.</p>
<p><em>Let's explain this step by step:</em></p>
<h3 id="heading-1-structure-and-layout"><strong>1. Structure and Layout</strong></h3>
<pre><code class="lang-swift"><span class="hljs-type">VStack</span> {
    <span class="hljs-type">HStack</span> {
        <span class="hljs-comment">// code..</span>
    }
}
</code></pre>
<h3 id="heading-2-profile-picture-selection"><strong>2. Profile Picture Selection</strong></h3>
<p>Create a photo picker to select an image. Default to a system icon <code>"person.circle.fill"</code> if no image is selected. The image should be resizable, mint-colored, clipped into a circle, and set to 100x100 pixels.</p>
<pre><code class="lang-swift"><span class="hljs-type">PhotosPicker</span>(selection: $photosPickerItem, matching: .not(.screenshots)) { 
    (avatarImage ?? <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"person.circle.fill"</span>))
        .resizable()
        .foregroundStyle(.mint)
        .aspectRatio(contentMode: .fit)
        .frame(width: <span class="hljs-number">100</span>, height: <span class="hljs-number">100</span>)
        .clipShape(.circle)
}
</code></pre>
<h3 id="heading-3-name-and-title"><strong>3. Name and Title</strong></h3>
<p>Display a name and job title.</p>
<pre><code class="lang-swift"><span class="hljs-type">VStack</span>(alignment: .leading) {
    <span class="hljs-type">Text</span>(<span class="hljs-string">"Sajid Hasan"</span>).font(.title.bold())
    <span class="hljs-type">Text</span>(<span class="hljs-string">"iOS Developer"</span>).bold().foregroundStyle(.secondary)
}
</code></pre>
<h3 id="heading-4-checking-for-image-playground-support"><strong>4. Checking for Image Playground Support</strong></h3>
<p>If the device supports <strong>Image Playground</strong>, display a text field and a button for generating an AI avatar. If not, provide appropriate feedback.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> supportsImagePlayground {
</code></pre>
<h3 id="heading-5-avatar-description-input"><strong>5. Avatar Description Input</strong></h3>
<p>Create a text input field for prompts to generate images and a button to trigger AI avatar creation.</p>
<pre><code class="lang-swift"><span class="hljs-type">TextField</span>(<span class="hljs-string">"Enter avatar description"</span>, text: $imageGenerationCooncept)
    .font(.title3.bold())
    .padding()
    .background(.quaternary, <span class="hljs-keyword">in</span>: .rect(cornerRadius: <span class="hljs-number">16</span>, style: .continuous))


<span class="hljs-type">Button</span>(<span class="hljs-string">"Generate Image"</span>, systemImage: <span class="hljs-string">"sparkles"</span>) {
    isShowingImagePlayground = <span class="hljs-literal">true</span>
}
.padding()
.foregroundStyle(.mint)
.fontWeight(.bold)
.background(
    <span class="hljs-type">RoundedRectangle</span>(cornerRadius: <span class="hljs-number">16</span>, style: .continuous)
        .stroke(.mint, lineWidth: <span class="hljs-number">3</span>)
)
</code></pre>
<h3 id="heading-6-handling-image-selection"><strong>6. Handling Image Selection</strong></h3>
<p>When the image is selected from photo picker, asynchronously load the image and update <code>avatarImage</code>.</p>
<pre><code class="lang-swift">.onChange(of: photosPickerItem) { <span class="hljs-number">_</span>, <span class="hljs-number">_</span> <span class="hljs-keyword">in</span>
    <span class="hljs-type">Task</span> {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> photosPickerItem, <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">try</span>? await photosPickerItem.loadTransferable(type: <span class="hljs-type">Data</span>.<span class="hljs-keyword">self</span>) {
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> image = <span class="hljs-type">UIImage</span>(data: data) { 
                avatarImage = <span class="hljs-type">Image</span>(uiImage: image) 
            }
        }
    }
}
</code></pre>
<h3 id="heading-7-using-image-playground"><strong>7. Using Image Playground</strong></h3>
<p>Present Image Playground sheet with prompt string and selected image. After AI processing, it will return a <strong>URL of the generated image</strong>.</p>
<pre><code class="lang-swift">.imagePlaygroundSheet(
    isPresented: $isShowingImagePlayground,
    concept: imageGenerationCooncept,
    sourceImage: avatarImage) { url <span class="hljs-keyword">in</span>
</code></pre>
<h3 id="heading-8-updating-the-avatar-with-ai-image"><strong>8. Updating the Avatar with AI Image</strong></h3>
<p>Loads the AI-generated image from the url and sets it as the new avatar image.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">try</span>? <span class="hljs-type">Data</span>(contentsOf: url) {
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> image = <span class="hljs-type">UIImage</span>(data: data) {
        avatarImage = <span class="hljs-type">Image</span>(uiImage: image)
    }
}
</code></pre>
<h3 id="heading-9-handling-cancellation"><strong>9. Handling Cancellation</strong></h3>
<p>Clear the description if the user cancels the AI avatar generation.</p>
<pre><code class="lang-swift">onCancellation: {
    imageGenerationCooncept = <span class="hljs-string">""</span>
}
</code></pre>
<h3 id="heading-10-build-something-diffrent">10. Build Something Diffrent</h3>
<div data-node-type="callout">
<div data-node-type="callout-emoji">🚀</div>
<div data-node-type="callout-text">This is just a simple implementation to show how Image Playground can be integrated into your app to enhance user experience. Explore the process and make something different with your creativity.</div>
</div>

<p>I would love to connect with you on LinkedIn. Here’s my profile: <a target="_blank" href="https://www.linkedin.com/in/sajidshanta/">https://www.linkedin.com/in/sajidshanta/</a></p>
<hr />
<p><em>More related resources:</em></p>
<p><a target="_blank" href="https://developer.apple.com/apple-intelligence/"><em>https://developer.apple.com/apple-intelligence/</em></a></p>
<p><a target="_blank" href="https://developer.apple.com/documentation/imageplayground"><em>https://developer.apple.com/documentation/imageplayground</em></a></p>
<p><a target="_blank" href="https://youtu.be/fjtWpQGs5lU?si=u1-qLRRuK2WSQdSA"><em>https://youtu.be/fjtWpQGs5lU?si=u1-qLRRuK2WSQdSA</em></a></p>
]]></content:encoded></item><item><title><![CDATA[How to Prepare for an iOS Developer Interview]]></title><description><![CDATA[Getting ready for an iOS Developer interview is more than just brushing up on your coding skills. It's about blending technical knowledge with design principles and effective communication. As an iOS Developer, you're creating experiences for million...]]></description><link>https://blog.sajidhasan.com/how-to-prepare-for-an-ios-developer-interview</link><guid isPermaLink="true">https://blog.sajidhasan.com/how-to-prepare-for-an-ios-developer-interview</guid><category><![CDATA[iOS]]></category><category><![CDATA[interview]]></category><category><![CDATA[ios app development]]></category><category><![CDATA[Interview tips]]></category><category><![CDATA[Swift]]></category><category><![CDATA[swift interview questions]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Tue, 09 Jul 2024 17:18:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720541258719/0762ebb7-b4b3-4b81-8419-f51249d49359.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Getting ready for an iOS Developer interview is more than just brushing up on your coding skills. It's about blending technical knowledge with design principles and effective communication. As an iOS Developer, you're creating experiences for millions of users, so it's important to showcase your coding abilities along with your understanding of user interface design, performance optimization, and the Apple ecosystem. A well-prepared candidate stands out by demonstrating a deep knowledge of iOS frameworks, a problem-solving mindset, and a passion for building intuitive and efficient applications.</p>
<hr />
<p>I've taken inspiration from <a target="_blank" href="https://www.tealhq.com/">Teal's website</a> for this article. I believe it will be helpful to share my insights and create a guide to assist fellow iOS developers in their upcoming interviews. Let's get started!</p>
<hr />
<h3 id="heading-steps-to-ace-your-ios-developer-interview">Steps to Ace Your iOS Developer Interview</h3>
<h4 id="heading-1-master-the-fundamentals">1. Master the Fundamentals</h4>
<p>Ensure you have a strong understanding of Swift or Objective-C. Comprehend core concepts such as memory management, concurrency, and error handling. Stay updated by reviewing the latest iOS SDK and Apple's Human Interface Guidelines.</p>
<h4 id="heading-2-understand-ios-specific-technologies">2. Understand iOS-Specific Technologies</h4>
<p>Familiarize yourself with essential frameworks and APIs such as UIKit, Core Data, and Core Animation. Know how to work with RESTful APIs and understand networking concepts within the context of an iOS app.</p>
<h4 id="heading-3-review-your-past-projects">3. Review Your Past Projects</h4>
<p>Be prepared to discuss your previous work, the challenges you faced, and how you overcame them. Highlight any unique solutions or optimizations you implemented.</p>
<h4 id="heading-4-practice-coding-challenges">4. Practice Coding Challenges</h4>
<p>Sharpen your problem-solving skills by tackling coding challenges on platforms like LeetCode or HackerRank, focusing on algorithms and data structures commonly used in mobile app development.</p>
<h4 id="heading-5-prepare-for-system-design-questions">5. Prepare for System Design Questions</h4>
<p>Understand how to design scalable systems. Be prepared to discuss architecture choices for hypothetical app scenarios, considering performance, maintainability, and user experience.</p>
<h4 id="heading-6-stay-updated-on-apples-ecosystem">6. Stay Updated on Apple's Ecosystem</h4>
<p>Keep up with the latest developments in the iOS world, including new features in the latest version of iOS, Swift language updates, and changes to the App Store guidelines.</p>
<h4 id="heading-7-mock-interviews">7. Mock Interviews</h4>
<p>Practice mock interviews focusing on technical, system design, and behavioral questions. Use feedback to improve your answers and presentation skills.</p>
<h4 id="heading-8-prepare-your-portfolio">8. Prepare Your Portfolio</h4>
<p>Have your portfolio of apps ready, preferably with links to the App Store or GitHub. Be prepared to explain your design and development process for each project.</p>
<h4 id="heading-9-develop-questions-to-ask">9. Develop Questions to Ask</h4>
<p>Prepare thoughtful questions about the company's tech stack, development processes, and culture. This demonstrates your interest in the role and helps you evaluate if the company is the right fit for you.</p>
<p>By following these steps, you will be prepared to address both the technical and non-technical aspects of the interview. Your preparation will enable you to confidently articulate your skills and experiences, thus making a strong impression on your potential employer. Best of luck with your interviews!</p>
<hr />
<p>Get prepared with my full iOS Interview Guide Blog Series:</p>
<p><a target="_blank" href="https://blog.sajidhasan.com/series/ios-interview">https://blog.sajidhasan.com/series/ios-interview</a></p>
<p><a target="_blank" href="https://blog.sajidhasan.com/series/ios-interview"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720544075449/11f6619d-d3e8-42d9-b5ae-bc869d5f07fe.jpeg" alt="iOS Interview Series by Sajid" class="image--center mx-auto" /></a></p>
<p>iOS Interview Series covers essential topics for mastering iOS development interviews, from Swift basics to advanced concepts.</p>
]]></content:encoded></item><item><title><![CDATA[Geometry Reader in SwiftUI: get a view's size and location]]></title><description><![CDATA[When developing SwiftUI applications, most of the time, we don't have to worry about the exact location or size of an item on the screen. However, there are cases where we need to ensure that certain items have specific sizes or locations on the app....]]></description><link>https://blog.sajidhasan.com/geometry-reader-in-swiftui-get-a-views-size-and-location</link><guid isPermaLink="true">https://blog.sajidhasan.com/geometry-reader-in-swiftui-get-a-views-size-and-location</guid><category><![CDATA[SwiftUI]]></category><category><![CDATA[Swift]]></category><category><![CDATA[iOS]]></category><category><![CDATA[ios app development]]></category><category><![CDATA[GeometryReader]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Mon, 20 Feb 2023 20:20:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1676922485869/ea3e06fe-48a3-4cff-8dad-94e54ea98942.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When developing SwiftUI applications, most of the time, we don't have to worry about the exact location or size of an item on the screen. However, there are cases where we need to ensure that certain items have specific sizes or locations on the app. This is where the Geometry Reader comes in.</p>
<p>Geometry Reader is a useful tool for any SwiftUI developer as it allows us to get the exact size and location of objects on the screen. Additionally, the GeometryReader is adaptive when the device rotates. It is the perfect helper if we want to resize our view when a user switches from portrait to landscape mode (or vice-versa).</p>
<p>Let's take a look at a basic example of how to use the Geometry Reader. We'll start with an HStack containing two rectangles, one coloured red and the other blue. By default, SwiftUI automatically resizes our objects to be the same size, but what if we want one rectangle to be two-thirds of the screen while the other is one-third?</p>
<p>Here's a code example:</p>
<pre><code class="lang-swift"><span class="hljs-type">HStack</span> {
  <span class="hljs-type">Rectangle</span>()
    .fill(<span class="hljs-type">Color</span>.red)
    .frame(width: <span class="hljs-type">UIScreen</span>.main.bounds.width * <span class="hljs-number">0.66</span>)

  <span class="hljs-type">Rectangle</span>()
    .fill(<span class="hljs-type">Color</span>.blue)
    .frame(width: <span class="hljs-type">UIScreen</span>.main.bounds.width * <span class="hljs-number">0.33</span>)
}
</code></pre>
<p>However, we'll quickly run into issues with this approach when we <strong><mark>rotate the device</mark></strong>. The width of the red rectangle is still two-thirds of the width of the device, even though it's not taking into account the device's new height. This is where Geometry Reader can help us.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676923937535/c99be8bf-7285-4454-85d1-d0688b038ca8.png" alt class="image--center mx-auto" /></p>
<p>Using Geometry Reader, we can dynamically calculate the size and location of the rectangles based on the current screen's dimensions, ensuring that they are always the correct size and in the correct location. Here's how we can update our previous example to use Geometry Reader:</p>
<pre><code class="lang-swift"><span class="hljs-type">HStack</span> {
  <span class="hljs-type">GeometryReader</span> { geo <span class="hljs-keyword">in</span>
    <span class="hljs-type">Rectangle</span>()
      .fill(<span class="hljs-type">Color</span>.red)
      .frame(width: geo.size.width * <span class="hljs-number">0.66</span>)
  }

  <span class="hljs-type">GeometryReader</span> { geo <span class="hljs-keyword">in</span>
    <span class="hljs-type">Rectangle</span>()
      .fill(<span class="hljs-type">Color</span>.blue)
      .frame(width: geo.size.width * <span class="hljs-number">0.33</span>)
  }
}
</code></pre>
<p>In this updated example, we're using two Geometry Readers to calculate the size of the rectangles dynamically. By passing in the <code>geo</code> parameter, we can access the size of the Geometry Reader and use it to calculate the width of each rectangle.</p>
<p>While the Geometry Reader can be a powerful tool for SwiftUI developers, it's essential to keep in mind that it can be expensive and slow down the UI when overused. It's best to try and build screens without using a Geometry Reader if possible, but if we do need to use one, make sure to use it sparingly.</p>
<p>In conclusion, the Geometry Reader is an incredibly useful tool for SwiftUI developers looking to add more dynamic animations and effects to their apps. With its ability to calculate the size and location of objects on the screen, we can make our apps more engaging and interactive, improving the user experience.</p>
]]></content:encoded></item><item><title><![CDATA[iOS App Life Cycle: Understanding App States with Real-Life Examples]]></title><description><![CDATA[Every app has its own unique life cycle that starts from the moment it's launched and ends when it's terminated. As Steve Jobs used to say, "Design is not just what it looks like and feels like. Design is how it works." Understanding the different ap...]]></description><link>https://blog.sajidhasan.com/ios-app-life-cycle</link><guid isPermaLink="true">https://blog.sajidhasan.com/ios-app-life-cycle</guid><category><![CDATA[ios app development]]></category><category><![CDATA[iOS]]></category><category><![CDATA[App states]]></category><category><![CDATA[App life cycle]]></category><category><![CDATA[Real-life examples]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Wed, 15 Feb 2023 12:36:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1677069051669/f99ecf56-6b19-4aeb-93da-5ef0906abd39.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every app has its own unique life cycle that starts from the moment it's launched and ends when it's terminated. As Steve Jobs used to say, "Design is not just what it looks like and feels like. Design is how it works." Understanding the different app states in the iOS app life cycle is essential for developing efficient and effective apps. In this blog, we will take a closer look at the iOS app life cycle and how an app transitions through its different states.</p>
<h1 id="heading-what-is-the-ios-app-life-cycle">What is the iOS App Life Cycle?</h1>
<p>The iOS app life cycle refers to the different states that an iOS app goes through as it is launched, runs, and eventually terminated by the user or the system. The app can be in one of 5 states: Not Running, Inactive, Active, Background, and Suspended. Let's explore these states in more detail.</p>
<p><img src="https://static.javatpoint.com/tutorial/ios/images/ios-app-lifecycle.png" alt="IOS app lifecycle - Javatpoint" class="image--center mx-auto" /></p>
<h1 id="heading-1-not-running-state">1. Not Running State:</h1>
<p>The Not Running state is when an app is not running at all. This is the app's initial state, and it's like when we haven't opened an app in a while or when we restart our phone. The app is not in memory and needs to be relaunched.</p>
<h1 id="heading-2-inactive-state">2. Inactive State:</h1>
<p>The Inactive state is when the app is in the foreground but is not receiving events. This can happen when a phone call interrupts the app, and the app will move to the Inactive state, allowing the phone call to take precedence over the app.</p>
<h1 id="heading-3-active-state">3. Active State:</h1>
<p>The Active state is when the app is in the foreground and is receiving events. This is the state in which an app spends most of its time, as it's actively being used by the user.</p>
<h1 id="heading-4-background-state">4. Background State:</h1>
<p>The Background state is when the app runs in the background and executes code. This is the state where an app transitions to when the user presses the Home button or switches to a different app.</p>
<h1 id="heading-5-suspended-state">5. Suspended State:</h1>
<p>The Suspended state is when the app is still in the background but is no longer executing code. The system can terminate the app in this state to free up resources.</p>
<h1 id="heading-real-life-examples">Real-Life Examples:</h1>
<p>Let's see some real-life examples of how the iOS app life cycle works.</p>
<p>Suppose you're using a messaging app, and you receive a notification from another app. In this case, the messaging app will move to the Inactive state, allowing the other app to display its notification. Once you're done with the notification, you'll go back to the messaging app, which will move back to the Active state.</p>
<p>Another example is when you're listening to music on your phone and then decide to browse the internet. As you switch to your browser, the music app will move to the Background state, and if you're not actively using the app for a while, it might move to the Suspended state.</p>
<h1 id="heading-wrap-up">Wrap-up</h1>
<p>In conclusion, Understanding the iOS app life cycle is essential for developing efficient and effective apps. By knowing how an app transitions through its different states, we can optimize our app's performance and make it more user-friendly. With these tips in mind, we can create innovative apps that stand out in the crowded world of app development. With Steve Jobs' words in mind, "Innovation distinguishes between a leader and a follower," it's crucial to stay innovative and up-to-date with the latest developments in app development.</p>
]]></content:encoded></item><item><title><![CDATA[Swift Documentation in Xcode: A Comprehensive Guide]]></title><description><![CDATA[Swift documentation in Xcode is a useful tool for documenting code, making it easier for other developers to understand and use. By adding clear and concise documentation, we can improve the readability and usability of our code and make it easier fo...]]></description><link>https://blog.sajidhasan.com/swift-documentation-in-xcode-a-comprehensive-guide</link><guid isPermaLink="true">https://blog.sajidhasan.com/swift-documentation-in-xcode-a-comprehensive-guide</guid><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[Xcode]]></category><category><![CDATA[documentation]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Sat, 07 Jan 2023 20:41:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1673119397817/1e468591-de6f-41e6-b31b-f8bbf94b2666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Swift documentation in Xcode is a useful tool for documenting code, making it easier for other developers to understand and use. By adding clear and concise documentation, we can improve the readability and usability of our code and make it easier for others to understand and use.</p>
<p>There are two methods to add documentation to our Swift code in Xcode: triple-slash <code>(///)</code> comments and block <code>(/** */)</code> comments.</p>
<h1 id="heading-triple-slash-comment">Triple-slash Comment (<code>///</code>)</h1>
<p>Triple-slash comments are typically used for concise, single-line documentation. They are displayed in the Quick Help panel in Xcode and are a quick way to add documentation for a specific piece of code.</p>
<p>Here is an example of triple-slash documentation for a function in Swift:</p>
<pre><code class="lang-swift"><span class="hljs-comment">/// Returns the sum of two numbers.</span>
<span class="hljs-comment">///</span>
<span class="hljs-comment">/// - Parameters:</span>
<span class="hljs-comment">///   - a: The first number.</span>
<span class="hljs-comment">///   - b: The second number.</span>
<span class="hljs-comment">/// - Returns: The sum of `a` and `b`.</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">add</span><span class="hljs-params">(a: Int, b: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
    <span class="hljs-keyword">return</span> a + b
}
</code></pre>
<h1 id="heading-block-comment">Block Comment (<code>/** */</code>)</h1>
<p>Block comments, denoted by <code>/** */</code>, are more suitable for longer, multi-line documentation. These comments are displayed as a standalone document in the documentation browser, allowing for more thorough explanations and examples.</p>
<p>Here is an example of block documentation for a class in Swift:</p>
<pre><code class="lang-swift"><span class="hljs-comment">/**
 A class for representing a point in 2D space.

 This class has two properties, `x` and `y`, which represent the coordinates of the point. It also has a computed property, `distanceFromOrigin`, which calculates the distance of the point from the origin.
*/</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Point</span> </span>{
    <span class="hljs-keyword">var</span> x: <span class="hljs-type">Double</span>
    <span class="hljs-keyword">var</span> y: <span class="hljs-type">Double</span>

    <span class="hljs-comment">/// The distance of the point from the origin.</span>
    <span class="hljs-keyword">var</span> distanceFromOrigin: <span class="hljs-type">Double</span> {
        <span class="hljs-keyword">return</span> sqrt(x * x + y * y)
    }

    <span class="hljs-keyword">init</span>(x: <span class="hljs-type">Double</span>, y: <span class="hljs-type">Double</span>) {
        <span class="hljs-keyword">self</span>.x = x
        <span class="hljs-keyword">self</span>.y = y
    }
}
</code></pre>
<p>It's important to note that proper documentation is a key part of good coding practice, as it helps other developers understand the purpose and functionality of our code. Both triple-slash and block comments are useful tools for adding documentation to our Swift code in Xcode.</p>
<h1 id="heading-last-words">Last Words</h1>
<p>In addition to describing the code itself, we can also use Swift documentation to include examples, notes, and other helpful information for users of our code. For example, we can include an example of how to use our function or class like this:</p>
<pre><code class="lang-swift"><span class="hljs-comment">/// Returns the sum of two numbers.</span>
<span class="hljs-comment">///</span>
<span class="hljs-comment">/// - Parameters:</span>
<span class="hljs-comment">///   - a: The first number.</span>
<span class="hljs-comment">///   - b: The second number.</span>
<span class="hljs-comment">/// - Returns: The sum of `a` and `b`.</span>
<span class="hljs-comment">///</span>
<span class="hljs-comment">/// - Example:</span>
<span class="hljs-comment">///     let sum = add(a: 1, b: 2)</span>
<span class="hljs-comment">///     print(sum) // prints "3"</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">add</span><span class="hljs-params">(a: Int, b: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
    <span class="hljs-keyword">return</span> a + b
}
</code></pre>
<p>we can also use special Markdown syntax to format our documentation in different ways. For example, we can use <code>**bold**</code> or <code>*italic*</code> text to emphasize certain words or phrases. We can also create lists using asterisks (<code>*</code>) or numbers like this:</p>
<pre><code class="lang-swift"><span class="hljs-comment">/**
 A list of things to do:

 * Take out the trash
 * Water the plants
 * Feed the dog
 * Do the laundry
 */</span>
</code></pre>
<p>In addition to these basic formatting options, we can also use Markdown to create tables, links, and other formatting elements. For a complete list of the Markdown syntax supported in Xcode documentation, you can refer to the "<a target="_blank" href="https://developer.apple.com/documentation/xcode/formatting-your-documentation-content"><strong>Formatting Your Documentation Content</strong></a><strong>"</strong> documentation on the Apple Developer website.</p>
]]></content:encoded></item><item><title><![CDATA[Five Effective Commenting Practices for Swift-iOS]]></title><description><![CDATA[It's essential to use comments in code to document our thought process and make it easier for others to understand our code. But comments will be more impactful when we maintain best practices (including when and what to write comments). This blog wi...]]></description><link>https://blog.sajidhasan.com/five-effective-commenting-practices-for-swift-ios</link><guid isPermaLink="true">https://blog.sajidhasan.com/five-effective-commenting-practices-for-swift-ios</guid><category><![CDATA[commenting Practice]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iOS]]></category><category><![CDATA[ios app development]]></category><dc:creator><![CDATA[Sajid Hasan Shanta]]></dc:creator><pubDate>Sat, 31 Dec 2022 17:03:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672357560587/a632d384-8e6d-40bf-b8ff-b973aa2e49f8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It's essential to use comments in code to document our thought process and make it easier for others to understand our code. But comments will be more impactful when we maintain best practices (including when and what to write comments). This blog will discuss best comment practices when working with SwiftUI on iOS application development.</p>
<p>If you are having difficulty understanding the comment examples in this blog post, don't worry. The primary focus of this blog is to understand the purpose of commenting. It is important for every good programmer to have a strong sense of when and how to comment on their code, and this blog aims to help you build that skill.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672358311972/c74228a7-0842-402d-b0c0-55ac211225de.jpeg" alt class="image--center mx-auto" /></p>
<p>Jokes apart, let's discuss the Five Effective "when and how":</p>
<h2 id="heading-1-explain-the-purpose-of-a-function-or-method">1. Explain the purpose of a function or method</h2>
<p>When writing a function or method, it's important to explain its purpose in a comment clearly. This will help other developers understand the purpose of the function and how it fits into the overall application.</p>
<p>For example:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// Returns current date in 'dd/mm/yyyy' format</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getCurrentDate</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">String</span> {
    <span class="hljs-comment">// code to get current date</span>
}
</code></pre>
<h2 id="heading-2-explain-complex-code">2. Explain complex code</h2>
<p>If we have written a complex piece of code that may be difficult for others to understand, it's helpful to include comments explaining the logic behind it. This will make it easier for others to follow our thought process and understand how the code functions.</p>
<p>Here is an example of a complex piece of code in Swift with comments explaining the logic behind it:</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">findLargestNumber</span><span class="hljs-params">(<span class="hljs-keyword">in</span> array: [Int])</span></span> -&gt; <span class="hljs-type">Int</span> {
    <span class="hljs-comment">// Initialize variables to track current largest number &amp; index</span>
    <span class="hljs-keyword">var</span> largest = array[<span class="hljs-number">0</span>]
    <span class="hljs-keyword">var</span> largestIndex = <span class="hljs-number">0</span>

    <span class="hljs-comment">// Iterate through array and update largest number and its index</span>
    <span class="hljs-keyword">for</span> (index, element) <span class="hljs-keyword">in</span> array.enumerated() {
        <span class="hljs-keyword">if</span> element &gt; largest {
            largest = element
            largestIndex = index
        }
    }

    <span class="hljs-comment">// Return the largest number</span>
    <span class="hljs-keyword">return</span> largest
}
</code></pre>
<p>In this example, the <code>findLargestNumber(in:)</code> function takes an array of integers as input and returns the largest number in the array. The comments above each block of code explain the purpose of the variables and the logic behind the for loop that iterates through the array and updates the largest number and its index. This will help other developers understand the code and follow the thought process behind it.</p>
<h2 id="heading-3-comments-to-document-changes">3. Comments to document changes</h2>
<p>If we make changes to our code, it's essential to document those changes in comments. This will help other developers understand the reasoning behind the changes and how they may impact the overall application.</p>
<p>Here is an example of using comments to document changes in Swift code:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// MARK: - Lifecycle</span>

<span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">viewDidLoad</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">super</span>.viewDidLoad()
    <span class="hljs-comment">// Added setup code for new feature</span>
    setUpNewFeature()
}

<span class="hljs-comment">// MARK: - New Feature</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">setUpNewFeature</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// Initialize and configure new feature</span>
    <span class="hljs-keyword">let</span> newFeature = <span class="hljs-type">NewFeature</span>()
    newFeature.configure()
}

<span class="hljs-comment">// MARK: - Changes Made</span>

<span class="hljs-comment">// - Added setUpNewFeature() to initialize and configure new feature</span>
<span class="hljs-comment">// - Added newFeature property to store the instance of new feature</span>
<span class="hljs-comment">// - Modified viewDidLoad() to call setUpNewFeature()</span>
</code></pre>
<p>In this example, we have added a new feature to our view controller and made some changes to the <code>viewDidLoad()</code> method to initialize and configure the new feature. We have also added a property to store the instance of the new feature. To document these changes, we have added a comment at the top of the block of code outlining the changes that were made, including the addition of the new function and the modifications to <code>viewDidLoad()</code>.</p>
<h2 id="heading-4-keep-comments-concise-and-relevant">4. Keep comments concise and relevant</h2>
<p>While it's important to include comments in our code, it's also important to keep them concise and relevant. Avoid writing long, unnecessary comments, as they can clutter our code and make it harder to read.</p>
<p>Here is an example of concise and relevant comments in Swift code:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// Calculate the distance between two points</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">distance</span><span class="hljs-params">(x1: Double, y1: Double, x2: Double, y2: Double)</span></span> -&gt; <span class="hljs-type">Double</span> {
    <span class="hljs-keyword">let</span> dx = x2 - x1
    <span class="hljs-keyword">let</span> dy = y2 - y1
    <span class="hljs-keyword">return</span> sqrt(dx*dx + dy*dy)
}

<span class="hljs-comment">// Check if a point is within a circle</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isInsideCircle</span><span class="hljs-params">(x: Double, y: Double, centerX: Double, centerY: Double, radius: Double)</span></span> -&gt; <span class="hljs-type">Bool</span> {
    <span class="hljs-comment">// Calculate the distance between the point and the center of the circle</span>
    <span class="hljs-keyword">let</span> <span class="hljs-built_in">distance</span> = <span class="hljs-keyword">self</span>.<span class="hljs-built_in">distance</span>(x1: x, y1: y, x2: centerX, y2: centerY)
    <span class="hljs-comment">// Return true if the distance is less than the radius, false otherwise</span>
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">distance</span> &lt; radius
}
</code></pre>
<p>In this example, we have defined two functions: <code>distance()</code> and <code>isInsideCircle()</code>. Both functions have concise and relevant comments that explain their purpose and how they work. The comment for <code>distance()</code> explains that it calculates the distance between two points, while the comment for <code>isInsideCircle()</code> explains that it checks if a point is within a circle by calculating the distance between the point and the center of the circle and comparing it to the radius of the circle. These comments help clarify the code's purpose and function, making it easier for other developers to understand and maintain.</p>
<h2 id="heading-5-use-comments-to-improve-readability">5. Use comments to improve readability</h2>
<p>In addition to explaining the purpose of our code, comments can also be used to enhance the readability of our code. For example, we can use comments to separate code sections or highlight important points.</p>
<p>Here is an example of using comments to improve readability in Swift code:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// MARK: - Data Loading</span>

<span class="hljs-comment">// Load data from the API</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">loadData</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// Make API call</span>
    <span class="hljs-type">API</span>.loadData { [<span class="hljs-keyword">weak</span> <span class="hljs-keyword">self</span>] result <span class="hljs-keyword">in</span>
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> <span class="hljs-keyword">self</span> = <span class="hljs-keyword">self</span> <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }
        <span class="hljs-keyword">switch</span> result {
        <span class="hljs-keyword">case</span> .success(<span class="hljs-keyword">let</span> data):
            <span class="hljs-comment">// Process and save the data</span>
            <span class="hljs-keyword">self</span>.processAndSaveData(data)
        <span class="hljs-keyword">case</span> .failure(<span class="hljs-keyword">let</span> error):
            <span class="hljs-comment">// Handle the error</span>
            <span class="hljs-keyword">self</span>.handleError(error)
        }
    }
}

<span class="hljs-comment">// Process and save the data</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">processAndSaveData</span><span class="hljs-params">(<span class="hljs-number">_</span> data: Data)</span></span> {
    <span class="hljs-comment">// Convert the data to a model object</span>
    <span class="hljs-keyword">let</span> model = <span class="hljs-keyword">try</span>? <span class="hljs-type">JSONDecoder</span>().decode(<span class="hljs-type">Model</span>.<span class="hljs-keyword">self</span>, from: data)
    <span class="hljs-comment">// Save the model object to Core Data</span>
    <span class="hljs-keyword">try</span>? <span class="hljs-type">CoreDataManager</span>.shared.save(model)
}

<span class="hljs-comment">// Handle the error</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">handleError</span><span class="hljs-params">(<span class="hljs-number">_</span> error: Error)</span></span> {
    <span class="hljs-comment">// Log the error</span>
    <span class="hljs-built_in">print</span>(<span class="hljs-string">"Error: \(error)"</span>)
}
</code></pre>
<p>In this example, we have a class with three functions: <code>loadData()</code>, <code>processAndSaveData()</code>, and <code>handleError()</code>. To improve the readability of the code, we have added comments to separate the different sections and to explain the purpose of each function. The <code>MARK</code> comment at the top of the block of code separates the <code>Data Loading</code> section from the rest of the code, while the comments above each function explain what the function does. These comments help to break up the code and make it easier to understand and follow.</p>
<h2 id="heading-last-words">Last Words</h2>
<p>In conclusion, following best comment practices when working with Swift on iOS application development is crucial for maintaining clean, well-documented code. By explaining the purpose of our code, documenting changes, and keeping comments concise and relevant, we can make it easier for us and others to understand and work with our code.</p>
<p>For any queries or suggestions, connect with me <a target="_blank" href="https://www.linkedin.com/in/sajidshanta/">here</a>.</p>
]]></content:encoded></item></channel></rss>