Examples of Delegates in Swift

Delegates in swift?

It is not that different from obj-c.
First, you have to specify the protocol in your class declaration, like following:

class MyClass: NSUserNotificationCenterDelegate

The implementation will look like following:

// NSUserNotificationCenterDelegate implementation
func userNotificationCenter(center: NSUserNotificationCenter, didDeliverNotification notification: NSUserNotification) {
//implementation
}

func userNotificationCenter(center: NSUserNotificationCenter, didActivateNotification notification: NSUserNotification) {
//implementation
}

func userNotificationCenter(center: NSUserNotificationCenter, shouldPresentNotification notification: NSUserNotification) -> Bool {
//implementation
return true
}

Of course, you have to set the delegate. For example:

NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self;

Examples of Delegates in Swift

What is Delegation?

First of all, you should know that Delegation Pattern is not exclusive for iOS world:

In software engineering, the delegation pattern is a design pattern in
object-oriented programming that allows object composition to achieve
the same code reuse as inheritance.

But working with delegation in the iOS world is so common, I assume that you can see many of classes that provide a delegation/datasource for giving the ability to provide properties or behaviors for the used instance. It is one of main mechanisms of how objects talk to each other in CocoaTouch.


Alternatives:

However, delegation is not the only way to let objects talk to each other in iOS, you might want to know that there are:

  • NotificationCenter.
  • KVO (Key-Value Observing).
  • Completion handlers/Callbacks (using closures).
  • Target-Action.

Remark: in case if you are interested in comparing between them, you might want to check the following articles:

  • Communication Patterns.
  • When to Use Delegation, Notification, or Observation in iOS.
  • Delegates vs Observers.

When to use Delegation?

So, the question is: "So why should I use delegation instead of those options?"

I will try to make it simple; I would suggest the use of delegation when you have one to one relationship between two objects. Just to make it clearer, the goal of talking a little bit about the NotificationCenter is to try to make sense when delegations are used:

NotificationCenter represents one to many relationship; Simply, it works as: posting (notifying) a notification on a specific event and observing (get notified about) this notification -- it could be observed anywhere else; Logically, that's what one to many relationship means. It is a representation of the Observer Pattern.


How to Apply Delegation?

For the purpose of simplifying, I would mention it as steps:

  1. Knowing the requirements: Each delegate has its own rules, listed in the delegate protocol which is a set of method signatures that you should implement for conforming this delegation.

  2. Conforming for the delegation: it is simply letting your class to be a delegate, by marking it. For instance: class ViewController: UIViewController, UITableViewDelegate {}.

  3. Connecting the delegate object: Marking your class to be a delegate is not enough, you need to make sure that the object you want to be confirmed by your class to give the required job to your class.

  4. Implementing the requirements: Finally, your class have to implement all required methods listed in the delegate protocol.


For Example

Does it sounds a little confusing? What about a real-world example?

Consider the following scenario:

Imagine that you are building an application related to playing audios. Some of the viewControllers should have a view of an audio player. In the simplest case, we assume that it should have a play/pause button and another button for, let's say, showing a playlist somehow, regardless of how it may look like.

So far so good, the audio player view has its separated UIView class and .xib file; it should be added as a subview in any desired viewController.

Now, how can you add functionality to both of the buttons for each viewController? You might think: "Simply, I will add an IBAction in the view class and that's it", at first look, it might sound ok, but after re-thinking a little bit, you will realize that it will not be applicable if you are trying to handle the event of tapping the button at the controller layer; To make it clear, what if each viewController implemented different functionality when tapping the buttons in the audio player view? For example: tapping the playlist in "A" viewController will display a tableView, but tapping it in the "B" viewController will display a picker.

Well, let's apply Delegation to this issue:

The "#" comments represents the steps of "How to Apply Delegation?" section.

Audio Player View:

// # 1: here is the protocol for creating the delegation
protocol AudioPlayerDelegate: class {
func playPauseDidTap()
func playlistDidTap()
}

class AudioPlayerView: UIView {
//MARK:- IBOutlets
@IBOutlet weak private var btnPlayPause: UIButton!
@IBOutlet weak private var btnPlaylist: UIButton!

// MARK:- Delegate
weak var delegate: AudioPlayerDelegate?

// IBActions
@IBAction private func playPauseTapped(_ sender: AnyObject) {
delegate?.playPauseDidTap()
}

@IBAction private func playlistTapped(_ sender: AnyObject) {
delegate?.playlistDidTap()
}
}

View Controller:

class ViewController: UIViewController {
var audioPlayer: AudioPlayerView?

// MARK:- Life Cycle
override func viewDidLoad() {
super.viewDidLoad()

audioPlayer = AudioPlayerView()
// # 3: the "AudioPlayerView" instance delegate will implemented by my class "ViewController"
audioPlayer?.delegate = self
}
}

// # 2: "ViewController" will implement "AudioPlayerDelegate":
extension ViewController: AudioPlayerDelegate {
// # 4: "ViewController" implements "AudioPlayerDelegate" requirments:
func playPauseDidTap() {
print("play/pause tapped!!")
}

func playlistDidTap() {
// note that is should do a different behavior in each viewController...
print("list tapped!!")
}
}



Quick Tip:

As one of the most popular examples of using delegation is Passing Data Back between View Controllers.

How can I write a simple example on how to use delegates in Swift 5

So the first error is because you are trying to call the delegate function, outside of anywhere it can be executed. You need to create a function that calls that function, or call it in init. When making examples, try using real world concepts to model your example. You could do something like a Conductor class and a Train Class. The conductor could implement some control protocol that controls the speed of the train.

Anyway, your second error is because self has not yet been initialized. to assign a variable to self, you must initialize the class first, so you could do

init() {
anything?.delegate = self
}

Feel free to DM to understand this concept more, i'll post a full example here in a bit.

EDIT: FULL EXAMPLE, feel free to ask questions

import Foundation

enum Direction {
case north
case east
case south
case west
}

protocol VehicleControls {
var speed: Float {get set}
var direction: Direction {get set}
var numPassengers: Int {get}

func change(newSpeed: Float)

func change(newDirection: Direction)

func createNoise()
}

class Conductor {
var vehicle: VehicleControls

init() {
vehicle = Train(s: 1.5, d: .west, nP: 50)
}

func controlVehicle() {
vehicle.change(newSpeed: 2.5)
vehicle.change(newDirection: .east)
vehicle.createNoise()
print("\n")
}
}

class Train: VehicleControls {
var speed: Float
var direction: Direction
var numPassengers: Int

init() {
self.speed = 0
self.direction = .north
self.numPassengers = 0
}

init(s: Float, d: Direction, nP: Int) {
self.speed = s
self.direction = d
self.numPassengers = nP
}

func change(newSpeed: Float) {
print("changing speed from \(speed), to \(newSpeed)")
self.speed = newSpeed
}

func change(newDirection: Direction) {
print("changing direction from \(direction) to \(newDirection)")
self.direction = newDirection
}

func createNoise() {
print("Chugga, Chugga... Chugga, Chugga... CHOO CHOO")
}
}

class Car: VehicleControls {
var speed: Float
var direction: Direction
var numPassengers: Int

init() {
self.speed = 0
self.direction = .north
self.numPassengers = 0
}

init(s: Float, d: Direction, nP: Int) {
self.speed = s
self.direction = d
self.numPassengers = nP
}

func change(newSpeed: Float) {
print("changing speed from \(speed), to \(newSpeed)")
self.speed = newSpeed
}

func change(newDirection: Direction) {
print("changing direction from \(direction) to \(newDirection)")
self.direction = newDirection
}

func createNoise() {
print("HONK HONK, BEEP BEEP")
}
}

let newConductor = Conductor()

newConductor.controlVehicle()

newConductor.vehicle = Car(s: 60.56, d: .north, nP: 2)

newConductor.controlVehicle()

Explain me delegation in Swift by a simple example

S0, as been told in comments:

– It doesn't work because your VC1 is nil in VC2

– It is bad practice to make one VC delegate of another

Simple theoretical example is:

You have class DataParser that loads some data from internet, doing parsing, making data to be treated as your models, saving it to local storage. It takes time. And your VC should present this data after all preparations done.

After job finished class DataParser should notify VC that it's done with data and VC is welcomed to show it.

Of course VC should "show" their interest, by implementing:

dataParser.delegate = self

Class is "looking for" some delegate, who is interested in his message:

delegate?.dataIsReadyToBeShown(with: data)

Delegate (VC here) gets data in

func dataIsReadyToBeShown(with data: AnyClass)

Simple swift delegate in swift playground

It doesn't print because the delegate is nil right after you set it. The reason for this is simple: no instance owns it (the reference count is zero). No one owns delegate because you declared it a weak property of OtherClass. Try establishing an ownership, e.g.

var myVar = OtherClass()
let viewController = MyViewController()
myVar.delegate = viewController

Even though delegate is weak, it will now print Something done again.

Declaring delegates as weak makes sense because it prevents circular references causing delegate to never be release in memory – that's a whole different story though – check how reference counting works, then you will understand why this is a good practice.

Implement delegates within SwiftUI Views

You need to create a view that conforms to UIViewControllerRepresentable and has a Coordinator that handles all of the delegate functionality.

For example, with your example view controller and delegates:

struct SomeDelegateObserver: UIViewControllerRepresentable {
let vc = SomeViewController()
var foo: (Data) -> Void
func makeUIViewController(context: Context) -> SomeViewController {
return vc
}

func updateUIViewController(_ uiViewController: SomeViewController, context: Context) { }
func makeCoordinator() -> Coordinator {
Coordinator(vc: vc, foo: foo)
}

class Coordinator: NSObject, SomeDelegate {
var foo: (Data) -> Void
init(vc: SomeViewController, foo: @escaping (Data) -> Void) {
self.foo = foo
super.init()
vc.delegate = self
}
func someDelegateFunction(data: Data) {
foo(data)
}
}
}

Usage:

struct ContentView: View {
var dataModel: DataModel

var body: some View {
NavigationLink(destination: CustomView(numberFromPreviousView: 10)) {
Text("Go to VCRepresentable")
}
}
}

struct CustomView: View {
@State var instanceData1: String = ""
@State var instanceData2: Data?
var numberFromPreviousView: Int // example of data passed from the previous view to this view, the one that can react to the delegate's functions
var body: some View {
ZStack {
SomeDelegateObserver { data in
print("Some delegate function was executed.")
self.instanceData1 = "Executed!"
self.instanceData2 = data
}
VStack {
Text("This is the UI")
Text("That, in UIKit, you would have in the UIViewController")
Text("That conforms to whatever delegate")
Text("SomeDelegateObserver is observing.")
Spacer()
Text(instanceData1)
}
}
}
}

Note: I renamed VCRepresentable to SomeDelegateObserver to be more indicative of what it does: Its sole purpose is to wait for delegate functions to execute and then run the closures (i.e foo in this example) you provide it. You can use this pattern to create as many functions as you need to "observe" whatever delegate functions you care about, and then execute code that can update the UI, your data model, etc. In my example, when SomeDelegate fires someDelegateFunction(data:), the view will display "Excuted" and update the data instance variable.

Unable to call another class method using delegate in swift

Because you instantiate instance of Class A using

    var objA = A()

Clearly you haven't initialised delegate property in A because its optional its default value is nil

Now when you call

    objA.delegate?.TestA()

delegate is nil hence function TestA will not be called

Suggestion

Always use camelCasing for declaring names of functions. So TestA() is incorrect rather use testA()

EDIT 1:

Tested this

@IBAction func btnClicked(_ sender: Any) {
let objA = A()
let objB = B()
objA.delegate = objB
objA.delegate?.TestA()
}

This is working fine what is the issue?

Swift using delegate tableview to refresh content from another class

Based in your code, you're not setting any value to your weak variable named delegate in Product class. You should set it to the class who should be using it.
One way is to make your Product class as singleton in a way that it will only initialize once.
e.g.

class Product {
static let shared = Product()
weak var delegate: ProductUpdateDelegate?

private init() { }

func getProductInfoFromAPI(){
if(result != "no_data")
self.delegate?.refreshTableView()
}
}

And in you tableview controller instead of let productInfo = Product() you can use let productInfo = Product.shared then set your delegate.

productInfo.delegate = self

That's it!



Related Topics



Leave a reply



Submit