Class Delegate Protocol

ID

swift.class_delegate_protocol

Severity

info

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Swift

Tags

delegation, reliability, retain_cycle

Description

Reports a protocol whose name ends in Delegate or DataSource but is not class-bound. Only a class-bound protocol (one that inherits AnyObject, the modern Swift form of the : class requirement) can be referenced through a weak or unowned property, which is the standard way to break the retain cycle inherent to the Cocoa delegation pattern.

protocol PlayerDelegate {              // FLAW — could be a struct, no weak ref
    func didFinish()
}

Rationale

A Cocoa-style delegate holds a back-reference to its owner. Without a weak reference, owner and delegate keep each other alive forever — the classic UIKit retain cycle. weak requires the referent to be a class instance; if the protocol could be satisfied by a struct or enum, the property cannot be weak, so callers are forced into strong references and into manual cleanup. Making the protocol class-bound shifts that constraint to where it belongs.

Remediation

Mark the protocol class-bound by inheriting AnyObject:

protocol PlayerDelegate: AnyObject {
    func didFinish()
}

This is the complement of swift.weak_delegate_references, which flags the property side (var delegate: PlayerDelegate missing weak).

When not to fire

The rule fires only on protocols whose name ends in Delegate or DataSource with at least one prefix character — the naming convention is the Cocoa / SwiftUI signal that the protocol is part of a delegation contract. Other protocols are not assumed to participate in retain cycles.