<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ashish Bhandari</title>
    <description>The latest articles on DEV Community by Ashish Bhandari (@iashishbhandari).</description>
    <link>https://dev.to/iashishbhandari</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2694154%2F71c3dbcb-d831-4aa5-8b59-cff1990385a9.jpg</url>
      <title>DEV Community: Ashish Bhandari</title>
      <link>https://dev.to/iashishbhandari</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iashishbhandari"/>
    <language>en</language>
    <item>
      <title>Building an On-Device Training Strategy for Personalized iOS Apps</title>
      <dc:creator>Ashish Bhandari</dc:creator>
      <pubDate>Sat, 13 Jun 2026 17:20:51 +0000</pubDate>
      <link>https://dev.to/iashishbhandari/building-an-on-device-training-strategy-for-personalized-ios-apps-3fai</link>
      <guid>https://dev.to/iashishbhandari/building-an-on-device-training-strategy-for-personalized-ios-apps-3fai</guid>
      <description>&lt;p&gt;Machine learning on mobile devices is often associated with inference: download a model, run predictions, and return results.&lt;/p&gt;

&lt;p&gt;But what if the model could continue learning directly on the user's device?&lt;/p&gt;

&lt;p&gt;In this article, I'll walk through a practical training strategy for on-device personalization in iOS using a lightweight Multilayer Perceptron (MLP). The goal is to create applications that adapt to individual users while keeping their data private and avoiding cloud infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Train On Device?
&lt;/h2&gt;

&lt;p&gt;Consider a habit-tracking application.&lt;/p&gt;

&lt;p&gt;Two users may exhibit completely different behaviors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User A completes habits every morning.&lt;/li&gt;
&lt;li&gt;User B completes habits late at night.&lt;/li&gt;
&lt;li&gt;User A responds well to reminders.&lt;/li&gt;
&lt;li&gt;User B ignores reminders entirely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A single global model cannot capture every user's unique patterns.&lt;/p&gt;

&lt;p&gt;Instead, we can train a small neural network locally using each user's own interaction history.&lt;/p&gt;

&lt;p&gt;Benefits include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Privacy-first personalization&lt;/li&gt;
&lt;li&gt;No server-side training costs&lt;/li&gt;
&lt;li&gt;Offline functionality&lt;/li&gt;
&lt;li&gt;Faster adaptation to user behavior&lt;/li&gt;
&lt;li&gt;Reduced regulatory concerns around user data&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Training Pipeline
&lt;/h2&gt;

&lt;p&gt;A typical on-device learning pipeline looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Events
    ↓
Feature Extraction
    ↓
Training Dataset
    ↓
MLP Training
    ↓
Updated Model
    ↓
Personalized Predictions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every user effectively owns a customized model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Collect Behavioral Signals
&lt;/h2&gt;

&lt;p&gt;Start by recording meaningful events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;UserEvent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Date&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EventType&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;EventType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;appOpened&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;reminderTapped&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;habitCompleted&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;habitSkipped&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These events can be stored using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SwiftData&lt;/li&gt;
&lt;li&gt;Core Data&lt;/li&gt;
&lt;li&gt;SQLite&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to build a historical timeline of user behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Build Feature Vectors
&lt;/h2&gt;

&lt;p&gt;Raw events aren't useful for neural networks.&lt;/p&gt;

&lt;p&gt;We need numerical features.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;HabitFeatures&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;currentStreak&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;completionRate30Days&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;appLaunchesToday&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;remindersOpenedToday&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;hourOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After normalization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="mf"&gt;0.45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mf"&gt;0.80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mf"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mf"&gt;0.75&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These values become the neural network's input.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Generate Training Samples
&lt;/h2&gt;

&lt;p&gt;Every day becomes a training example.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Features on Monday
        ↓
Completed Habit on Tuesday?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Represented as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;TrainingSample&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 = completed habit&lt;/li&gt;
&lt;li&gt;0 = missed habit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Over time the device accumulates hundreds of examples automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Keep the Model Small
&lt;/h2&gt;

&lt;p&gt;On-device learning is not about training giant models.&lt;/p&gt;

&lt;p&gt;A compact MLP is often sufficient:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10 Inputs
    ↓
16 Neurons
    ↓
8 Neurons
    ↓
1 Output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This architecture typically contains only a few hundred parameters.&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast training&lt;/li&gt;
&lt;li&gt;Tiny memory footprint&lt;/li&gt;
&lt;li&gt;Low battery usage&lt;/li&gt;
&lt;li&gt;Instant predictions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 5: Schedule Training Intelligently
&lt;/h2&gt;

&lt;p&gt;One of the biggest mistakes in mobile ML is training too frequently.&lt;/p&gt;

&lt;p&gt;Training should happen only under favorable conditions.&lt;/p&gt;

&lt;p&gt;Recommended conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Device charging&lt;/li&gt;
&lt;li&gt;Connected to Wi-Fi&lt;/li&gt;
&lt;li&gt;Screen locked&lt;/li&gt;
&lt;li&gt;User inactive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use BackgroundTasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;BGProcessingTaskRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"com.example.training"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Training should typically run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once per day&lt;/li&gt;
&lt;li&gt;Once per week&lt;/li&gt;
&lt;li&gt;After collecting enough new samples&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;epochs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;span class="n"&gt;batchSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;
&lt;span class="n"&gt;learningRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.001&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This usually completes in under a second for small datasets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Save Model Checkpoints
&lt;/h2&gt;

&lt;p&gt;After training, persist the updated weights.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ModelCheckpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Codable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kt"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;biases&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store checkpoints inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application Support/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On launch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadCheckpoint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model immediately resumes from its previous state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Run Fast Local Inference
&lt;/h2&gt;

&lt;p&gt;Predictions should happen in real time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;probability&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;features&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.87
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meaning:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The user has an 87% probability of completing today's habit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Inference latency for small MLPs is typically less than one millisecond on modern iPhones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Convert Predictions into Product Decisions
&lt;/h2&gt;

&lt;p&gt;Predictions only become valuable when they drive experiences.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;probability&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;scheduleReminder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;probability&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;suppressReminder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application becomes adaptive rather than rule-based.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Learning
&lt;/h2&gt;

&lt;p&gt;The most powerful aspect of on-device learning is the feedback loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Predict
    ↓
Observe Outcome
    ↓
Store Example
    ↓
Retrain
    ↓
Improve Predictions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every interaction helps improve the model.&lt;/p&gt;

&lt;p&gt;No data ever leaves the device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Privacy by Design
&lt;/h2&gt;

&lt;p&gt;Traditional personalization systems often require:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Device
    ↓
Cloud
    ↓
Training
    ↓
Predictions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An on-device system looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Device
    ↓
Training
    ↓
Predictions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;User behavior never leaves the phone.&lt;/p&gt;

&lt;p&gt;This dramatically improves privacy while reducing infrastructure complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Not every application needs a transformer, a recommendation engine, or a cloud-based ML platform.&lt;/p&gt;

&lt;p&gt;Many personalization problems can be solved with a small neural network trained directly on the user's device.&lt;/p&gt;

&lt;p&gt;For habit tracking, content recommendations, notification timing, fitness coaching, and user engagement prediction, a lightweight MLP combined with background training can deliver highly personalized experiences while remaining fast, private, and inexpensive to operate.&lt;/p&gt;

&lt;p&gt;The future of mobile AI isn't only about larger models. Sometimes it's about making smaller models personal.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>machinelearning</category>
      <category>mobile</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>From PyTorch to Core ML: My Journey Running Recommendation Models Directly on iPhone</title>
      <dc:creator>Ashish Bhandari</dc:creator>
      <pubDate>Fri, 12 Jun 2026 13:30:45 +0000</pubDate>
      <link>https://dev.to/iashishbhandari/from-pytorch-to-core-ml-my-journey-running-recommendation-models-directly-on-iphone-2jfn</link>
      <guid>https://dev.to/iashishbhandari/from-pytorch-to-core-ml-my-journey-running-recommendation-models-directly-on-iphone-2jfn</guid>
      <description>&lt;p&gt;Most recommendation systems run entirely on the backend. User interactions are sent to servers, models generate recommendations, and results are returned to the client.&lt;/p&gt;

&lt;p&gt;Recently, I explored a different approach: running recommendation inference directly on an iPhone using a Two-Tower model and Core ML.&lt;/p&gt;

&lt;p&gt;The goal wasn't to replace backend recommendation systems, but to understand the feasibility, trade-offs, and developer experience of on-device personalization.&lt;/p&gt;

&lt;p&gt;Here's what I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why On-Device Inference?
&lt;/h2&gt;

&lt;p&gt;Traditional recommendation flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Action
    ↓
 Backend
    ↓
 ML Model
    ↓
 Recommendations
    ↓
 Mobile App
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach works well, but comes with a few challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network latency&lt;/li&gt;
&lt;li&gt;Backend inference costs&lt;/li&gt;
&lt;li&gt;Privacy concerns&lt;/li&gt;
&lt;li&gt;Offline limitations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With on-device inference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Features
    ↓
 Core ML Model
    ↓
 Recommendation Embedding
    ↓
 Local Ranking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the recommendation logic executes directly on the device.&lt;/p&gt;

&lt;p&gt;Benefits include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Near-instant inference&lt;/li&gt;
&lt;li&gt;Reduced backend dependency&lt;/li&gt;
&lt;li&gt;Better privacy&lt;/li&gt;
&lt;li&gt;Offline recommendation capabilities&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understanding the Two-Tower Architecture
&lt;/h2&gt;

&lt;p&gt;Before implementation, I spent time understanding why Two-Tower architectures are widely used in recommendation systems.&lt;/p&gt;

&lt;p&gt;The model consists of:&lt;/p&gt;

&lt;h3&gt;
  
  
  User Tower
&lt;/h3&gt;

&lt;p&gt;Generates a user embedding from features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User ID&lt;/li&gt;
&lt;li&gt;Purchase history&lt;/li&gt;
&lt;li&gt;Preferences&lt;/li&gt;
&lt;li&gt;Behavioral signals
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Features
      ↓
  User Tower
      ↓
 User Embedding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Item Tower
&lt;/h3&gt;

&lt;p&gt;Generates embeddings for products.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Product Features
       ↓
   Item Tower
       ↓
 Product Embedding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Matching
&lt;/h3&gt;

&lt;p&gt;Recommendations are generated by comparing embeddings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Similarity(
    User Embedding,
    Product Embedding
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Products with higher similarity scores are ranked higher.&lt;/p&gt;

&lt;p&gt;This architecture is particularly attractive because item embeddings can be precomputed and stored, leaving only user embedding generation to happen on-device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Converting the Model to Core ML
&lt;/h2&gt;

&lt;p&gt;One of the first challenges was model conversion.&lt;/p&gt;

&lt;p&gt;I initially assumed that converting a PyTorch model into Core ML would be straightforward.&lt;/p&gt;

&lt;p&gt;Reality was slightly different.&lt;/p&gt;

&lt;p&gt;A common issue was discovering that the downloaded &lt;code&gt;.pt&lt;/code&gt; file contained only model weights (&lt;code&gt;state_dict&lt;/code&gt;) rather than the actual architecture.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model.pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderedDict&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which meant the model architecture had to be reconstructed before conversion.&lt;/p&gt;

&lt;p&gt;After rebuilding the model and exporting it through Core ML Tools, I obtained:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TwoTower.mlpackage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which could be integrated directly into an iOS project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating with Xcode
&lt;/h2&gt;

&lt;p&gt;Importing the model into Xcode automatically generated Swift bindings.&lt;/p&gt;

&lt;p&gt;One lesson I learned was not to assume generated class names.&lt;/p&gt;

&lt;p&gt;I initially tried:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UserTower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which failed because Xcode generated classes based on the model package name rather than internal tower names.&lt;/p&gt;

&lt;p&gt;The generated class was actually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;TwoTower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A small detail, but one that cost more debugging time than I'd like to admit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Inference
&lt;/h2&gt;

&lt;p&gt;Once integrated, inference became surprisingly simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;prediction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prediction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Core ML runtime handled execution using available hardware accelerators.&lt;/p&gt;

&lt;p&gt;The developer experience was significantly smoother than expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Observations
&lt;/h2&gt;

&lt;p&gt;The most impressive part was latency.&lt;/p&gt;

&lt;p&gt;Since inference happened locally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No network request&lt;/li&gt;
&lt;li&gt;No API dependency&lt;/li&gt;
&lt;li&gt;No server round-trip&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user experience felt immediate.&lt;/p&gt;

&lt;p&gt;For recommendation systems, even a few hundred milliseconds can impact engagement.&lt;/p&gt;

&lt;p&gt;On-device inference effectively removes an entire network hop from the critical path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges I Encountered
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Model Conversion
&lt;/h3&gt;

&lt;p&gt;This was by far the biggest challenge.&lt;/p&gt;

&lt;p&gt;Questions that frequently came up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the model TorchScript?&lt;/li&gt;
&lt;li&gt;Is it only a state dictionary?&lt;/li&gt;
&lt;li&gt;What are the expected input shapes?&lt;/li&gt;
&lt;li&gt;Which outputs are generated?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The conversion pipeline often requires more ML engineering knowledge than mobile engineering knowledge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Input Feature Engineering
&lt;/h3&gt;

&lt;p&gt;A recommendation model is only as useful as the features provided.&lt;/p&gt;

&lt;p&gt;Preparing inputs consistently between training and inference environments is critical.&lt;/p&gt;

&lt;p&gt;Even small mismatches can significantly affect recommendation quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging Core ML Models
&lt;/h3&gt;

&lt;p&gt;Debugging application code is easy.&lt;/p&gt;

&lt;p&gt;Debugging machine learning outputs is harder.&lt;/p&gt;

&lt;p&gt;When recommendations look wrong, the issue could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data preprocessing&lt;/li&gt;
&lt;li&gt;Feature encoding&lt;/li&gt;
&lt;li&gt;Model conversion&lt;/li&gt;
&lt;li&gt;Training quality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finding the root cause requires a systematic approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Surprised Me Most
&lt;/h2&gt;

&lt;p&gt;Before this project, I assumed recommendation systems were too heavy for mobile devices.&lt;/p&gt;

&lt;p&gt;The reality is that modern phones are extremely capable.&lt;/p&gt;

&lt;p&gt;For many personalization use cases, running lightweight recommendation models directly on-device is entirely practical.&lt;/p&gt;

&lt;p&gt;The challenge isn't necessarily inference performance.&lt;/p&gt;

&lt;p&gt;The challenge is building the surrounding ecosystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Feature pipelines&lt;/li&gt;
&lt;li&gt;Embedding storage&lt;/li&gt;
&lt;li&gt;Ranking strategies&lt;/li&gt;
&lt;li&gt;Model updates&lt;/li&gt;
&lt;li&gt;Experimentation frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Two-Tower architectures are well-suited for on-device recommendation systems.&lt;/li&gt;
&lt;li&gt;Core ML integration is easier than expected once the model is correctly converted.&lt;/li&gt;
&lt;li&gt;Model conversion is often the hardest part of the workflow.&lt;/li&gt;
&lt;li&gt;On-device inference dramatically reduces latency.&lt;/li&gt;
&lt;li&gt;Privacy and offline capabilities become significant advantages.&lt;/li&gt;
&lt;li&gt;The surrounding recommendation infrastructure is usually more complex than the inference itself.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This project started as an exploration into mobile machine learning and quickly became a deeper lesson in recommendation systems.&lt;/p&gt;

&lt;p&gt;As mobile hardware continues to improve, I expect more personalization workloads to move closer to the user.&lt;/p&gt;

&lt;p&gt;Running recommendation inference directly on-device won't replace backend recommendation systems entirely, but it opens interesting possibilities for low-latency, privacy-preserving, and offline-first user experiences.&lt;/p&gt;

&lt;p&gt;For mobile engineers interested in machine learning, Two-Tower models and Core ML are an excellent place to start.&lt;/p&gt;

</description>
      <category>deeplearning</category>
      <category>ios</category>
      <category>machinelearning</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Weak References in Swift: Understanding Retention Behavior with XCTest</title>
      <dc:creator>Ashish Bhandari</dc:creator>
      <pubDate>Sun, 12 Jan 2025 11:13:08 +0000</pubDate>
      <link>https://dev.to/iashishbhandari/weak-references-in-swift-understanding-retention-behavior-with-xctest-1gik</link>
      <guid>https://dev.to/iashishbhandari/weak-references-in-swift-understanding-retention-behavior-with-xctest-1gik</guid>
      <description>&lt;p&gt;In Swift, managing object references and memory correctly is essential for building efficient and leak-free applications. One of the most useful tools for preventing retain cycles and ensuring proper memory management is the &lt;strong&gt;weak reference&lt;/strong&gt;. But how exactly does a weak reference behave, and how can we test it to ensure it works as expected?&lt;/p&gt;

&lt;p&gt;In this post, we'll dive into &lt;strong&gt;weak references&lt;/strong&gt; in Swift and provide a practical demonstration using &lt;strong&gt;XCTest&lt;/strong&gt; to test their behavior. Specifically, we’ll look at how to verify that a weak reference retains an object initially but does not retain the object after it is deallocated.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Weak Reference?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;weak reference&lt;/strong&gt; in Swift is a reference to an object that &lt;strong&gt;does not retain&lt;/strong&gt; the object it points to. This is useful for preventing &lt;strong&gt;retain cycles&lt;/strong&gt;, where two objects strongly reference each other, preventing either from being deallocated. With weak references, the object it points to can still be deallocated, and when that happens, the weak reference &lt;strong&gt;automatically becomes &lt;code&gt;nil&lt;/code&gt;&lt;/strong&gt;. This behavior is different from &lt;strong&gt;strong references&lt;/strong&gt;, which keep the object alive as long as there is a reference to it.&lt;/p&gt;

&lt;p&gt;Key points about weak references:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They &lt;strong&gt;do not retain&lt;/strong&gt; the object.&lt;/li&gt;
&lt;li&gt;If the object they point to is deallocated, the reference &lt;strong&gt;becomes &lt;code&gt;nil&lt;/code&gt;&lt;/strong&gt; automatically.&lt;/li&gt;
&lt;li&gt;They are typically used when an object should not own or strongly retain another, such as in &lt;strong&gt;delegate&lt;/strong&gt; relationships or when dealing with &lt;strong&gt;circular dependencies&lt;/strong&gt; in complex data structures.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Implementation
&lt;/h3&gt;

&lt;p&gt;Here’s the implementation of the &lt;code&gt;WeakReference&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;WeakReference&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;AnyObject&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why This is Important
&lt;/h3&gt;

&lt;p&gt;Understanding the behavior of weak references is crucial when designing systems that rely on memory management, especially when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are working with delegate patterns where the child object should not strongly retain its parent.&lt;/li&gt;
&lt;li&gt;You are implementing circular references in data models (such as doubly linked lists or graphs).&lt;/li&gt;
&lt;li&gt;You need to ensure that resources are freed properly when an object is no longer needed, preventing &lt;strong&gt;memory leaks&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Test Case: Verifying Weak Reference Behavior
&lt;/h2&gt;

&lt;p&gt;In the following example, we will write unit tests using &lt;strong&gt;XCTest&lt;/strong&gt; to verify that a &lt;strong&gt;weak reference&lt;/strong&gt; behaves as expected in two key scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initially, a weak reference should retain the object while it exists.&lt;/li&gt;
&lt;li&gt;After the object is deallocated, the weak reference should automatically become &lt;code&gt;nil&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s the implementation of the &lt;code&gt;WeakReferenceTests&lt;/code&gt; class that contains the tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;XCTest&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;WeakReferenceTests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;XCTestCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;testWeakReferenceRetainsObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TestObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;TestObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// Creating an object&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;WeakReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Creating a weak reference&lt;/span&gt;

        &lt;span class="kt"&gt;XCTAssertNotNil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Weak reference should retain the object while it exists."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;testWeakReferenceDoesNotRetainObjectAfterDeallocation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TestObject&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;TestObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// Creating an object&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;WeakReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Creating a weak reference&lt;/span&gt;

        &lt;span class="kt"&gt;XCTAssertNotNil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Weak reference should retain the object initially."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Deallocate the test object&lt;/span&gt;
        &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;

        &lt;span class="kt"&gt;XCTAssertNil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Weak reference should not retain the object once the object is deallocated."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;TestObject&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By writing tests like the ones above, you can confirm that your weak references work as expected and that your application’s memory management is functioning correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the Tests
&lt;/h3&gt;

&lt;p&gt;When running these tests, you would observe the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In &lt;code&gt;testWeakReferenceRetainsObject()&lt;/code&gt;&lt;/strong&gt;, the weak reference should hold onto the object, so the assertion will pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In &lt;code&gt;testWeakReferenceDoesNotRetainObjectAfterDeallocation()&lt;/code&gt;&lt;/strong&gt;, after the object is deallocated, the weak reference should automatically become &lt;code&gt;nil&lt;/code&gt;. If it does, the test will pass.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Weak references are a powerful tool for managing memory in Swift. They help prevent retain cycles and ensure that objects are deallocated when they are no longer needed.&lt;/p&gt;

&lt;p&gt;By writing unit tests like the ones shown above, you can ensure that your Swift code handles memory management correctly and efficiently, preventing &lt;strong&gt;memory leaks&lt;/strong&gt; and &lt;strong&gt;retain cycles&lt;/strong&gt; in your applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/iashishbhandari/WeakReference" rel="noopener noreferrer"&gt;https://github.com/iashishbhandari/WeakReference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy coding and testing!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
