What is a Delegate in Swift?

In this article, you will learn about what Delegate is and how it works.

What is Delegation?

As the name implies, delegation gives control to other objects. To make it happen, the delegate object has to be assigned to control other objects.

In iOS apps, the UIApplicaitonDelegate is an example. UIApplicationDelegate allows you to modify iOS behavior, such as receiving push notifications, opening URLs, and launching apps.

A delegation pattern ensures the functionality that needs to be delegated is provided.

Delegate patterns enable objects to communicate back to their owners decoupled from their code. It is much easier to reuse and maintain code if an object does not have to know the concrete type of its owner.

What is The Protocol in Swift?

A protocol acts as a tool to combine properties and methods into a single entity so that other objects can conform to this protocol to delegate tasks.

We can implement the properties and functions of protocols that can be provided by a class, structure, or enumeration in Swift. It is said to conform to a protocol if any of these types meet its requirements.

The Syntax For Creating a Protocol

Syntax

protocol <protocol_name> {
   // define the required methods here
}

As shown above, we gave a protocol name to our protocol which is specified using the protocol keyword in Swift. By defining your methods based on the protocol's requirements, you can define the protocol's purpose.

Creating a Delegate Object

Let?s try to understand how to use delegate in ImageDownloader class. I keep an optional reference to the delegate object (of type ImageDownloader) to allow an ImageDownloader class instance to operate without a delegate. If the delegate member variable is nil, ImageDownloader still downloads a file and still calls its own didDownloadImage() method.

<div class="code-mirror  language-swift" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;"><span class="token keyword">import</span> <span class="token class-name">UIKit</span>
<span class="token keyword">class</span> <span class="token class-name">ImageDownloader</span> <span class="token punctuation">{</span>
   <span class="token keyword">var</span> urlString<span class="token punctuation">:</span> <span class="token class-name">String</span>
   <span class="token keyword">var</span> downloadedImage<span class="token punctuation">:</span> <span class="token class-name">UIImage</span><span class="token operator">?</span>
   <span class="token keyword">var</span> delegate<span class="token punctuation">:</span> <span class="token class-name">ImageDownloaderDelegate</span><span class="token operator">?</span>
   <span class="token keyword">init</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> urlString<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">self</span><span class="token punctuation">.</span>urlString <span class="token operator">=</span> urlString
   <span class="token punctuation">}</span>
   <span class="token keyword">func</span> <span class="token function-definition function">downloadImage</span><span class="token punctuation">(</span><span class="token punctuation">)</span>     
      <span class="token comment">// downloading image</span>
      <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span><span class="token function">global</span><span class="token punctuation">(</span>qos<span class="token punctuation">:</span> <span class="token class-name">DispatchQoS</span><span class="token punctuation">.</span><span class="token class-name">QoSClass</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span>
         <span class="token keyword">let</span> imageURL <span class="token operator">=</span> <span class="token function">URL</span><span class="token punctuation">(</span>string<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">.</span>urlString<span class="token punctuation">)</span>
         <span class="token keyword">let</span> imageData <span class="token operator">=</span> <span class="token class-name">NSData</span><span class="token punctuation">(</span>contentsOf<span class="token punctuation">:</span> imageURL<span class="token operator">!</span><span class="token punctuation">)</span>
         <span class="token keyword">self</span><span class="token punctuation">.</span>downloadedImage <span class="token operator">=</span> <span class="token class-name">UIImage</span><span class="token punctuation">(</span>data<span class="token punctuation">:</span> imageData<span class="token operator">!</span> <span class="token keyword">as</span> <span class="token class-name">Data</span><span class="token punctuation">)</span>
    
         <span class="token comment">// update UI action on main thread</span>
         <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span>
            <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">didDownloadImage</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
         <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">func</span> <span class="token function-definition function">didDownloadImage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      delegate<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">didFinishDownloading</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">)</span>
   <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</div>

Creating a Protocol

Using the ImageDownloader class, we will define a protocol to notify conformed objects when a task is completed or failed. This protocol will have a set of rules (or functions).

A class, struct, or enum can conform to the protocol and complete the implementation of these functions.

In this example, we will conform to the ImageDownloaderDelegate protocol in the ProfileController class. Now, we need to set the delegate object to ProfileController?s object.

Make sure that the required functions are implemented in the ProfileController class. Otherwise, the compiler will report an error.

<div class="code-mirror  language-swift" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;"><span class="token keyword">import</span> <span class="token class-name">UIKit</span>
<span class="token comment">// Protocol Creation</span>
<span class="token keyword">protocol</span> <span class="token class-name">ImageDownloaderDelegate</span> <span class="token punctuation">{</span>
    
   <span class="token comment">// notify when downloading will be finished</span>
   <span class="token keyword">func</span> <span class="token function-definition function">didFinishDownloading</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> sender<span class="token punctuation">:</span> <span class="token class-name">ImageDownloader</span><span class="token punctuation">)</span>
    
   <span class="token comment">// notify when downloading will be failed</span>
   <span class="token keyword">func</span> <span class="token function-definition function">didFailedDownloading</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> sender<span class="token punctuation">:</span> <span class="token class-name">ImageDownloader</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</div>

Conforming to This Delegate

Now, the ProfileController class conforms to the ImageDownloaderDelegate protocol.

<div class="code-mirror  language-swift" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;"><span class="token keyword">class</span> <span class="token class-name">ProfileController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span><span class="token punctuation">,</span> <span class="token class-name">ImageDownloaderDelegate</span> <span class="token punctuation">{</span>
   <span class="token keyword">private</span> <span class="token keyword">var</span> imageDownloader<span class="token punctuation">:</span> <span class="token class-name">ImageDownloader</span><span class="token operator">?</span>
   <span class="token keyword">private</span> <span class="token keyword">let</span> profileImageView <span class="token operator">=</span> <span class="token class-name">UIImageView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
   <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      view<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>profileImageView<span class="token punctuation">)</span>
      <span class="token comment">// set profileImageView frame here as per requirement</span>
      <span class="token function">downloadImage</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">downloadImage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">let</span> imageURL<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"<https://image_url_here>.com"</span></span>
      imageDownloader <span class="token operator">=</span> <span class="token class-name">ImageDownloader</span><span class="token punctuation">(</span>imageURL<span class="token punctuation">)</span>
      imageDownloader<span class="token operator">?</span><span class="token punctuation">.</span>delegate <span class="token operator">=</span> <span class="token keyword">self</span>
      imageDownloader<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">downloadImage</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">func</span> <span class="token function-definition function">didFinishDownloading</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> sender<span class="token punctuation">:</span> <span class="token class-name">ImageDownloader</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      profileImageView<span class="token punctuation">.</span>image <span class="token operator">=</span> sender<span class="token punctuation">.</span>downloadedImage
      <span class="token keyword">let</span> urlString <span class="token operator">=</span> sender<span class="token punctuation">.</span>urlString
      <span class="token function">print</span><span class="token punctuation">(</span>urlString<span class="token punctuation">)</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">func</span> <span class="token function-definition function">didFailedDownloading</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> sender<span class="token punctuation">:</span> <span class="token class-name">ImageDownloader</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      profileImageView<span class="token punctuation">.</span>image <span class="token operator">=</span> <span class="token nil constant">nil</span>
   <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</div>

How to Make The Optional Protocol Method?

You can include optional methods in your protocol. You have to create an extension for your optional protocol methods.

<div class="code-mirror  language-swift" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;"><span class="token comment">// protocol creation</span>
<span class="token keyword">protocol</span> <span class="token class-name">ImageDownloaderDelegate</span> <span class="token punctuation">{</span>
    
   <span class="token comment">// notify when downloading will be finish</span>
   <span class="token keyword">func</span> <span class="token function-definition function">didFinishDownloading</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> sender<span class="token punctuation">:</span> <span class="token class-name">ImageDownloader</span><span class="token punctuation">)</span>
    
   <span class="token comment">// notify when downloading will be failed</span>
   <span class="token keyword">func</span> <span class="token function-definition function">didFailedDownloading</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> sender<span class="token punctuation">:</span> <span class="token class-name">ImageDownloader</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">extension</span> <span class="token class-name">ImageDownloaderDelegate</span> <span class="token punctuation">{</span>
    
   <span class="token keyword">func</span> <span class="token function-definition function">didFailedDownloading</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> sender<span class="token punctuation">:</span> <span class="token class-name">ImageDownloader</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        
   <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</div>

Conclusion

You delegate work to someone/something else who can do it. Delegation helps you separate concerns, decouple classes, and make your code more reusable. The best place to start with delegation is between your view and your view controller

Updated on: 2022-12-21T15:25:33+05:30

5K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements