A meta library to provide a better `Delegate` pattern.

Related tags

Utility Delegate
Overview

Delegate

A meta library to provide a better Delegate pattern described here and here.

Usage

Instead of a regular Apple's protocol-delegate pattern, use a simple Delegate object to communicate:

class ClassA {
    let onDone = Delegate<(), Void>()

    func doSomething() {
        // ...
        onDone()
    }
}

class MyClass {
    func askClassAToDoSomething() {
        let a = ClassA()
        a.onDone.delegate(on: self) { (self, _) in
            self.jobDone()
        }
        a.doSomething()
    }

    private func jobDone() {
        print("๐ŸŽ‰")
    }
}

Why

Compare to regular delegation

Delegate does the same thing with much less code and compact structure. Just compare with the same work above in a formal protocol-delegate pattern.

protocol ClassADelegate {
    func doSomethingIsDone()
}

class ClassA {
    weak var delegate: ClassADelegate?

    func doSomething() {
        // ...
        delegate?.doSomethingIsDone()
    }
}

class MyClass {
    func askClassAToDoSomething() {
        let a = ClassA()
        a.delegate = self
        a.doSomething()
    }

    private func jobDone() {
        print("๐ŸŽ‰")
    }
}

extension MyClass: ClassADelegate {
    func doSomethingIsDone() {
        self.jobDone()
    }
}

No one loves to write boilerplate code, do you?

Compared to onXXX property

At the first glance, you may think Delegate is an over-work and can be replaced by a stored property like this:

class ClassA {
    var onDoneProperty: (() -> Void)?
    //...
}

It creates a strong holding, and I found it is really easy to create an unexpected cycle:

class MyClass {
    var a: ClassA = ClassA()

    func askClassAToDoSomething() {
        a.onDoneProperty = {
            // Retain cycle!!
            self.jobDone()
        }
    }

You have to remember [weak self] for most cases to break the cycle, it also requires you to check self before using it:

class MyClass {
    var a: ClassA = ClassA()

    func askClassAToDoSomething() {
        a.onDoneProperty = { [weak self] in
            guard let self = self else { return }
            self.jobDone()
        }
    }

Boilerplate code again! And things would become more complicated if the onDoneProperty needs to holds caller across multiple layers.

How

Delegate holds the target in a weak way internally, and provide a "strongified" shadowed version of the target to you when the delegate is called. So you can get the correct memory management for free and focus on your work with no boilerplate code at all.

a.onDone.delegate(on: self) { // This `self` is the delegation target. `onDone` holds a weak ref of it.
    (self, _) in                 // This `self` is a shadowed, non-option type.
    self.jobDone()            // Using of this `self` does not create retain cycle.
}

To pass some parameters or receive a return type, just declared the Delegate's generic types:

class DataController {
    let onShouldShowAtIndexPath = Delegate<IndexPath, Bool>()

    func foo() {
        let currentIndexPath: IndexPath = // ...
        let shouldShow: Bool = onShouldShowAtIndexPath(currentIndexPath)
        if shouldShow {
            show()
        }
    }
}

// Caller Side
dataSource.onShouldShowAtIndexPath.delegate(on: self /* : Target */ ) { (self, indexPath) in
    // This block has a type of `(Target, IndexPath) -> Bool`.
    return indexPath.row != 0
}

Caution

The only caution is, please always use the shadowed self in the delegation block. Say, this would cause a regression to the old onXXX property way and causes a retain cycle:

a.onDone.delegate(on: self) { (_, _) in
    self.jobDone()
}

It seems that you can use the "same" self, but actually in the code above you are using the "real" strong self. Do not mark the first input parameter of block as _ and always give it a name of self then you can prevent this.

To Do

  • Async support.
You might also like...
Butterfly is a lightweight library for integrating bug-report and feedback features with shake-motion event.
Butterfly is a lightweight library for integrating bug-report and feedback features with shake-motion event.

Butterfly is a lightweight library for integrating bug-report and feedback features with shake-motion event. Goals of this project One of th

Focus is an Optics library for Swift (where Optics includes Lens, Prisms, and Isos)

Focus Focus is an Optics library for Swift (where Optics includes Lens, Prisms, and Isos) that is inspired by Haskell's Lens library. Introduction Foc

๐Ÿ“˜A library for isolated developing UI components and automatically taking snapshots of them.
๐Ÿ“˜A library for isolated developing UI components and automatically taking snapshots of them.

A library for isolated developing UI components and automatically taking snapshots of them. Playbook Playbook is a library that provides a sandbox for

A Swift micro library for generating Sunrise and Sunset times.

Solar A Swift helper for generating Sunrise and Sunset times. Solar performs its calculations locally using an algorithm from the United States Naval

Plugin and runtime library for using protobuf with Swift

Swift Protobuf Welcome to Swift Protobuf! Apple's Swift programming language is a perfect complement to Google's Protocol Buffer ("protobuf") serializ

A Swift package for rapid development using a collection of micro utility extensions for Standard Library, Foundation, and other native frameworks.
A Swift package for rapid development using a collection of micro utility extensions for Standard Library, Foundation, and other native frameworks.

ZamzamKit ZamzamKit is a Swift package for rapid development using a collection of micro utility extensions for Standard Library, Foundation, and othe

ResponderChain is a library that passes events using the responder chain.

ResponderChain ResponderChain is a library that passes events using the responder chain.

RResultBuilder is DSL library based on Result Builder
RResultBuilder is DSL library based on Result Builder

RResultBuilder is DSL library based on Result Builder Features Requirements Installation Usage Screenshot Example Contribute Meta Feat

noppefoxwolf/notion is a notion.so API library written in swift.
noppefoxwolf/notion is a notion.so API library written in swift.

notion noppefoxwolf/notion is a notion.so API library written in swift. Installation Xcode Project Swift Packages [email protected]:noppefoxwolf/notion

Owner
Wei Wang
Developer, creator, proud father.
Wei Wang
SuggestionsBox helps you build better a product trough your user suggestions. Written in Swift. ๐Ÿ—ณ

SuggestionsBox An iOS library to aggregate users feedback about suggestions, features or comments in order to help you build a better product. Swift V

Manuel Escrig 100 Feb 6, 2022
๐Ÿš€Comprehensive Redux library for SwiftUI, ensures State consistency across Stores with type-safe pub/sub pattern.

??Comprehensive Redux library for SwiftUI, ensures State consistency across Stores with type-safe pub/sub pattern.

Cheng Zhang 18 Mar 9, 2022
FluxCapacitor makes implementing Flux design pattern easily with protocols and typealias.

FluxCapacitor makes implementing Flux design pattern easily with protocols and typealias. Storable protocol Actionable protocol Dispatch

Taiki Suzuki 123 Aug 23, 2022
A SARS-CoV-2 Mutation Pattern Query Tool

vdb A SARS-CoV-2 Mutation Pattern Query Tool 1. Purpose The vdb program is designed to query the SARS-CoV-2 mutational landscape. It runs as a command

null 13 Oct 25, 2022
Swordinator is a simple way of integrating an iOS Coordinator pattern.

Swordinator is a minimal, lightweight and easy customizable navigation framework for iOS applications. Requirements iOS 14.0+, Swift 5.0+ Installation

Timotheus Laubengaier 10 Oct 17, 2022
Cross-Platform, Protocol-Oriented Programming base library to complement the Swift Standard Library. (Pure Swift, Supports Linux)

SwiftFoundation Cross-Platform, Protocol-Oriented Programming base library to complement the Swift Standard Library. Goals Provide a cross-platform in

null 620 Oct 11, 2022
ZIP Foundation is a library to create, read and modify ZIP archive files.

ZIP Foundation is a library to create, read and modify ZIP archive files. It is written in Swift and based on Apple's libcompression for high performa

Thomas Zoechling 1.9k Dec 27, 2022
macOS system library in Swift

SystemKit A macOS system library in Swift based off of libtop, from Apple's top implementation. For an example usage of this library, see dshb, a macO

null 323 Jan 5, 2023
Swift library to develop custom Alexa Skills

AlexaSkillsKit AlexaSkillsKit is a Swift library that allows you to develop custom skills for Amazon Alexa, the voice service that powers Echo. It tak

Claus Hรถfele 170 Dec 27, 2022
๐Ÿน Bow is a cross-platform library for Typed Functional Programming in Swift

Bow is a cross-platform library for Typed Functional Programming in Swift. Documentation All documentation and API reference is published in our websi

Bow 613 Dec 20, 2022