Delegate — är ett designmönster där ett objekt delegerar utförandet av uppgifter till ett annat objekt via ett protokoll med fördefinierade metoder. Inom iOS-utveckling är Delegate ett av de grundläggande mönstren i Cocoa Touch, som används för asynkron meddelande utan direkt koppling mellan avsändare och mottagare. Enligt Apple Documentation (2025) tillämpas delegering i Foundation och UIKit för bearbetning av tabellhändelser, nätverksförfrågningar och platshantering. Mönstret säkerställer lös koppling av komponenter och återanvändning av kod.
Huvudpunkter
Delegate (delegat) — är ett objekt som implementerar ett specifikt protokoll och tar emot meddelanden om händelser från ett annat objekt. Delegation-mönstret är ett alternativ till arv: istället för att skapa en underklass för att åsidosätta metoder, delegerar objektet bearbetning av händelser till ett externt objekt. I iOS implementeras delegation via Swift-protokoll med obligatoriska och valfria metoder. Egenskapen delegate deklareras alltid som weak var för att undvika cykliska referenser mellan objekt.
Delegate-protokollet definierar interaktionskontraktet mellan objekt. Obligatoriska metoder måste implementeras av delegaten, annars kompileras inte koden. Valfria metoder markeras med attributet @objc optional och tillåter delegaten att reagera endast på nödvändiga händelser. Metodnamn följer konventionen: första parametern — avsändarobjektet, andra — händelsedata. Till exempel indikerar tableView(_:didSelectRowAt:) att avsändaren är UITableView och datan är index för den valda raden.
// Delegate-protokoll
protocol DownloadManagerDelegate: AnyObject {
func downloadManager(_ manager: DownloadManager,
didFinishWith data: Data)
func downloadManager(_ manager: DownloadManager,
didFailWith error: Error)
@objc optional func downloadManager(_ manager: DownloadManager,
didUpdateProgress progress: Float)
}
// Klass som använder Delegate
class DownloadManager {
weak var delegate: DownloadManagerDelegate?
func startDownload(from url: URL) {
URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
guard let self else { return }
if let error = error {
self.delegate?.downloadManager(self, didFailWith: error)
} else if let data = data {
self.delegate?.downloadManager(self, didFinishWith: data)
}
}.resume()
}
}
Egenskapen delegate måste deklareras som weak var (svag pekare) för att förhindra retain cycle. Om referensen var stark skulle delegaten och det delegerande objektet hålla fast varandra och ARC skulle inte kunna frigöra deras minne. Delegate-protokoll ärver AnyObject (endast för klasser), vilket möjliggör användning av weak. Strukturer och enum kan inte vara delegater på grund av värdessemantik. Alternativ för value types — callback closures.
class ViewController: DownloadManagerDelegate {
let manager = DownloadManager()
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self // weak — ingen retain cycle
manager.startDownload(from: url)
}
func downloadManager(_ manager: DownloadManager, didFinishWith data: Data) {
processData(data)
}
func downloadManager(_ manager: DownloadManager, didFailWith error: Error) {
showError(error)
}
}
Delegate-mönstret fungerar enligt principen ”en-till-en”: ett avsändarobjekt kan bara ha en delegat åt gången. När en händelse inträffar kontrollerar avsändaren om delegate är inställd och anropar motsvarande protokollmetod. Fördel jämfört med direkt anrop — avsändaren känner inte till delegatens typ, bara att den överensstämmer med protokollet. Detta följer principen om beroendeinversion (DIP) från SOLID.
Delegaten sätts via tilldelning: someObject.delegate = self. Vid frigöring av delegaten blir egenskapen automatiskt nil på grund av weak-semantik. Innan delegate-metoden anropas kontrolleras det via optional chaining: delegate?.method(). Om delegate är nil — ignoreras anropet utan krasch. För valfria protokollmetoder används en extra kontroll: delegate?.responds(to: #selector(...)), även om denna kontroll i Swift vanligtvis är implicit genom deklaration av valfri metod.
I en flertrådig miljö används delegate för asynkron återkoppling av resultat. URLSession tillhandahåller URLSessionDelegate med metoder som anropas vid mottagning av data, timeout eller autentiseringsfel. Delegate-metoder körs i URLSessions bakgrundskö, så dirigering till main queue krävs för UI-uppdateringar. Asynkron delegate blockerar inte den anropande tråden, vilket möjliggör fortsättning av andra uppgifter.
class NetworkService: NSObject, URLSessionDataDelegate {
private lazy var session = URLSession(
configuration: .default,
delegate: self,
delegateQueue: OperationQueue()
)
private var receivedData = Data()
func urlSession(_ session: URLSession,
dataTask: URLSessionDataTask,
didReceive data: Data) {
receivedData.append(data)
let progress = Float(receivedData.count) / Float(expectedSize)
DispatchQueue.main.async {
self.progressHandler?(progress)
}
}
func urlSession(_ session: URLSession,
task: URLSessionTask,
didCompleteWithError error: Error?) {
if let error = error {
delegate?.networkService(self, didFailWith: error)
} else {
delegate?.networkService(self, didReceive: receivedData)
}
}
}
Delegate och Callback löser samma uppgift — asynkron meddelande — men på olika sätt. Delegate använder ett protokoll med namngivna metoder, callback — en closure med kontextfångst. Valet beror på antalet händelser, komplexiteten hos signaturer och arkitektoniska preferenser. Apple rekommenderar delegate för API:er med flera händelser (UITableView — 20+ metoder) och callback för engångsslutföranden.
Delegate är att föredra när flera olika händelser från en källa behöver bearbetas. Till exempel meddelar CLLocationManager delegaten om platsförändring, behörighetsfel, in-/utträde ur geografiska zoner och förändring av tjänstestatus. Varje händelse är en separat protokollmetod med tydligt namn och typade parametrar. Delegate är också bekväm för konfiguration av beteende (should, will, did-metoder).
Callback är enklare för engångsförfrågningar med ett resultat. Completion handler i URLSession.dataTask upptar en rad vid anropspunkten jämfört med minst tre protokollmetoder. Callback är också mer naturlig för funktionella kedjor (map, flatMap, async/await). Vid nästling av mer än 2-3 nivåer blir dock callback Callback Hell, medan delegate alltid förblir platt.
iOS SDK innehåller dussintals inbyggda delegate-protokoll för olika delsystem. Var och en är utformad för ett specifikt interaktionsscenario. Enligt Apple Documentation (2025) är de mest använda delegaterna UITableViewDelegate, UITextFieldDelegate, CLLocationManagerDelegate, URLSessionDelegate och UNUserNotificationCenterDelegate. Dessa protokoll innehåller 3 till 30 metoder med varierande grad av obligatoriskhet.
UITableViewDelegate hanterar utseendet och beteendet hos tabellceller. Innehåller metoder för bearbetning av radval, inställning av cellhöjd, anpassade header/footer-vyer och svepaktioner. Alla protokollmetoder är valfria, vilket möjliggör implementering av endast nödvändig funktionalitet. I avsaknad av delegat fungerar tabellen med standardinställningar. Historiskt kombinerades delegate med UITableViewDataSource.
URLSessionDelegate ger detaljerad kontroll över HTTP-förfrågningar. Delegatens metoder anropas vid mottagning av serversvar, data, slutförande av nedladdning. Specialiserade underprotokoll URLSessionTaskDelegate och URLSessionDataDelegate utökar grundfunktionaliteten för specifika uppgiftstyper. Delegate krävs för stöd av bakgrundsnedladdningar, SSL-certifikat och anpassad bearbetning av omdirigeringar.
| Delegate | Metoder | Ändamål |
|---|---|---|
| UITableViewDelegate | 25 | Utseende och interaktion med tabell |
| UITextFieldDelegate | 8 | Bearbetning av textinmatning och tangentbord |
| CLLocationManagerDelegate | 12 | Platsuppdatering och geografiska zoner |
| URLSessionDelegate | 6 | Hantering av HTTP-session och certifikat |
| UNUserNotificationCenterDelegate | 4 | Bearbetning av push-meddelanden i förgrunden |
Minneshantering är en kritisk aspekt av att arbeta med delegate i iOS. ARC (Automatic Reference Counting) hanterar minnet automatiskt, men endast med korrekt användning av weak/unowned-referenser. Brott mot reglerna leder till minnesläckor eller förtida frigöring. Delegate deklarerad som strong skapar en retain cycle om ägaren av delegaten också håller en referens till det delegerande objektet.
Retain cycle uppstår när objekt A (ägaren) sätter sig själv som delegat för objekt B, och B håller en stark referens till delegate. Exempel: ViewController skapar URLSession, sätter self som delegat för sessionen, men URLSession håller som standard en stark referens till delegate om ingen delegateQueue anges. Lösning — kontrollera alltid API-dokumentationen för typen av referens till delegate (weak eller strong) och nollställ delegate explicit i deinit.
class SafeViewController: UIViewController {
private var session: URLSession?
private var service: NetworkService?
override func viewDidLoad() {
super.viewDidLoad()
service = NetworkService()
service?.delegate = self
}
deinit {
// Nollställning av delegate i deinit — best practice
service?.delegate = nil
session?.invalidateAndCancel()
}
}
// URLSession med weak delegate via NSObject
class WeakDelegateSession: NSObject {
private weak var delegate: URLSessionDelegate?
func createSession() -> URLSession {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
return URLSession(
configuration: .default,
delegate: self,
delegateQueue: queue
)
}
}
Innan delegatens metod anropas måste man kontrollera att delegaten finns (inte nil) och implementerar den anropade metoden. För obligatoriska protokollmetoder krävs ingen kontroll — kompilatorn garanterar implementering. För valfria metoder använd respond(to:) eller optional chaining. Om delegaten har frigjorts blir weak-referensen automatiskt nil och delegatanropet ignoreras. Detta är säkert beteende som inte kräver ytterligare bearbetning.
Utvecklare gör ofta misstag när de arbetar med Delegate-mönstret, särskilt i början av att lära sig iOS. Vanligast: retain cycle på grund av strong delegate, glömma att anropa delegate?.method(), felaktig signatur på protokollmetoder, inställning av delegate efter start av operation och flertrådiga kollisioner. Låt oss titta på varje misstag och sätt att förebygga dem.
Det mest kritiska misstaget — att deklarera delegate-egenskapen som strong var istället för weak var. Detta skapar en retain cycle där varken delegaten eller det delegerande objektet kan frigöras. Konsekvenser: minnesläcka, applikationsfördröjning och dolda buggar. Lösning: använd alltid weak var för delegate och låt protokollet ärva AnyObject för att utesluta användning av value types som delegat.
Om delegate sätts efter anrop av en asynkron metod kan de första händelserna gå förlorade. Exempel: anrop av startDownload() före tilldelning av manager.delegate = self leder till förlust av slutförandecallback om nedladdningen utförs synkront eller mycket snabbt. Lösning: sätt delegate före anrop av den asynkrona metoden och dokumentera initialiseringsordningen i protokollkommentarerna.
Vanliga frågor
Weak förhindrar retain cycle mellan delegaten och det delegerande objektet. Om referensen var stark skulle objekten hålla fast varandra och ARC skulle inte kunna frigöra dem. Weak-referens blir automatiskt nil vid frigöring av delegaten. Detta är standardpraxis i Cocoa Touch sedan Objective-Cs uppkomst och har bevarats i Swift för bakåtkompatibilitet.
Delegate bearbetar händelser och hanterar beteende (cellhöjd, reaktion på klick). DataSource tillhandahåller data för visning (antal rader, celler). Delegate svarar på frågan “hur?”, dataSource — på frågan “vad?”. I iOS implementeras båda via protokoll, ofta i samma kontroller, men konceptuellt separerade.
Nej, om protokollet ärver AnyObject (klassprotokoll). Weak-referenser är endast tillgängliga för reference types (klasser). För value types (struct, enum) använd callback closures eller en separat wrapper-klass. Om du kontrollerar protokollet kan du låta bli att ärva AnyObject, men då är weak förbjudet — välj medvetet mellan weak-delegate och struct-delegat.
responds(to:) — är en metod i NSObjectProtocol som kontrollerar om objektet implementerar den angivna selektorn. Används för att kontrollera valfria @objc-protokollmetoder före anrop. Utan denna kontroll leder anrop av en oimplementerad valfri metod till NSInvalidArgumentException. I Swift för protokoll med @objc optional kan kontrollen vara implicit via optional binding.
Nej, delegate är ett delegationsmönster, inte en singleton. Till skillnad från en singleton kan delegaten bytas ut under körning och finns i en instans för varje delegerande objekt. Ett objekt kan vara delegat för flera avsändare. Singleton är ett skapandemönster som garanterar en unik instans av en klass och har inget att göra med delegering.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också