Delegate: มันคืออะไร, รูปแบบการมอบหมายและโปรโตคอล iOS

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-02-17 เวลาอ่าน: 9 นาที

Delegate เป็นรูปแบบการออกแบบที่ออบเจกต์หนึ่งมอบหมายการทำงานให้กับอีกออบเจกต์หนึ่ง ใน iOS รูปแบบนี้ถูกนำไปใช้ผ่านโปรโตคอล Swift และ @protocol Objective-C การมอบหมายเป็นหนึ่งในรูปแบบพื้นฐานของ Cocoa Touch ที่ใช้ใน UITableViewDelegate, UITextFieldDelegate และ API อื่นๆ ของ Apple อีกนับร้อย ตามเอกสารสำหรับนักพัฒนา Apple (2025) ประมาณ 70% ของคลาสระบบ UIKit ใช้ดีลิเกตเพื่อปรับแต่งพฤติกรรมโดยไม่ต้องสืบทอด

ประเด็นสำคัญ

  • Delegate — รูปแบบที่ออบเจกต์ A มอบหมายการทำงานให้กับออบเจกต์ B ผ่านโปรโตคอลหรืออินเทอร์เฟซ
  • โปรโตคอล Swift กำหนดชุดของเมธอดที่ดีลิเกตสามารถหรือต้องนำไปใช้
  • การอ้างอิงแบบอ่อน (weak) ไปยังดีลิเกตจำเป็นเพื่อป้องกัน retain cycle และหน่วยความจำรั่ว
  • UITableViewDelegate — ตัวอย่างดีลิเกตที่พบบ่อยที่สุดใน iOS โดยมีเมธอดแบบเลือกได้มากกว่า 20 รายการ
  • ความแตกต่างจาก Observer: ดีลิเกตเป็นความสัมพันธ์แบบ 1:1 ในขณะที่การแจ้งเตือนทำงานบนหลักการ 1:N

รูปแบบ Delegate คืออะไร?

Delegate เป็นรูปแบบการออกแบบเชิงพฤติกรรมที่ช่วยให้ออบเจกต์สามารถมอบหมายความรับผิดชอบบางส่วนให้กับออบเจกต์อื่น ไม่เหมือนกับการสืบทอดที่คลาสลูกเขียนทับเมธอดของคลาสพ่อแม่ ดีลิเกตใช้การประกอบ (composition): ออบเจกต์เจ้าของเก็บการอ้างอิงไปยังดีลิเกตและเรียกเมธอดของมันในจุดที่กำหนด

ดีลิเกตกำหนด โปรโตคอล — ชุดของเมธอดที่ดีลิเกตสามารถนำไปใช้ เมธอดแบ่งออกเป็นแบบบังคับ (required) และแบบเลือกได้ (optional) ใน Swift เมธอดโปรโตคอลแบบเลือกได้จะถูกทำเครื่องหมายด้วยคีย์เวิร์ด @objc optional

วิธีการทำงานของดีลิเกต

ออบเจกต์ A (เจ้าของ) มีคุณสมบัติ delegate — การอ้างอิงแบบอ่อนไปยังออบเจกต์ B (ดีลิเกต) เมื่อเกิดเหตุการณ์ขึ้น A จะตรวจสอบว่า B นำเมธอดโปรโตคอลที่เกี่ยวข้องไปใช้หรือไม่และเรียกมัน การอ้างอิงแบบอ่อน จำเป็น: หากไม่มีมัน ดีลิเกตจะไม่สามารถถูกปลดปล่อยจากหน่วยความจำได้เพราะเจ้าของเก็บมันไว้ด้วยการอ้างอิงแบบแข็ง

Swift
protocol LoaderDelegate: AnyObject {
    func loaderDidStart(_ loader: DataLoader)
    func loader(_ loader: DataLoader, didLoad data: Data)
    func loader(_ loader: DataLoader, didFailWith error: Error)
}

class DataLoader {
    weak var delegate: LoaderDelegate?
    
    func start() {
        delegate?.loaderDidStart(self)
        // การโหลดแบบอะซิงโครนัส
    }
}

คลาส DataLoader กำหนดโปรโตคอล LoaderDelegate และเรียกเมธอดดีลิเกตในจุดสำคัญของวงจรการโหลด AnyObject รับประกันว่าโปรโตคอลสามารถนำไปใช้ได้โดยคลาสเท่านั้น — ซึ่งจำเป็นสำหรับการอ้างอิงแบบอ่อน

Delegate ทำงานอย่างไรใน Swift?

การนำดีลิเกตไปใช้ใน Swift ประกอบด้วยสามขั้นตอน: การประกาศโปรโตคอล การสร้างคุณสมบัติ delegate แบบอ่อนในเจ้าของ และการนำโปรโตคอลไปใช้ในคลาสดีลิเกต มาดูตัวอย่าง UITextField แบบกำหนดเองพร้อมการตรวจสอบความถูกต้อง

Swift
protocol ValidatorDelegate: AnyObject {
    func validate(_ input: String) -> Bool
    func validatorDidFail(_ input: String)
}

class ValidatedTextField: UITextField {
    weak var validator: ValidatorDelegate?
    
    override func textDidChange() {
        guard let text = self.text else { return }
        if validator?.validate(text) == false {
            validator?.validatorDidFail(text)
            self.layer.borderColor = UIColor.red.cgColor
        }
    }
}

class LoginViewController: UIViewController, ValidatorDelegate {
    let textField = ValidatedTextField()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        textField.validator = self
    }
    
    func validate(_ input: String) -> Bool {
        return input.count >= 6
    }
    
    func validatorDidFail(_ input: String) {
        print("การตรวจสอบล้มเหลว: อินพุตสั้นเกินไป")
    }
}

LoginViewController นำโปรโตคอล ValidatorDelegate ไปใช้และกำหนดตัวเองเป็นดีลิเกตของ textField ทุกครั้งที่มีการเปลี่ยนแปลงข้อความ ValidatedTextField จะเรียก validate(_:) และหากการตรวจสอบล้มเหลว — validatorDidFail(_:) ตัวควบคุมทำหน้าที่เป็นตัวกลางระหว่าง View และตรรกะการตรวจสอบ

Delegate เทียบกับ NotificationCenter เทียบกับ Closure

การเลือกระหว่างดีลิเกต การแจ้งเตือน และ closure ขึ้นอยู่กับจำนวนผู้รับและการเชื่อมต่อของส่วนประกอบ แต่ละกลไกแก้ปัญหาการสื่อสารระหว่างออบเจกต์ แต่มีข้อแลกเปลี่ยนที่แตกต่างกัน

คุณลักษณะDelegateNotificationCenterClosure
ประเภทการสื่อสาร1:11:N1:1
การเชื่อมต่ออ่อน (ผ่านโปรโตคอล)อ่อนมาก (คีย์สตริง)ปานกลาง (การจับบริบท)
ความปลอดภัยของชนิดสมบูรณ์ไม่มี (Any?)สมบูรณ์
ความเสี่ยง retain cycleไม่มี (weak)ไม่มีมี (การจับ self)
เมื่อใดควรใช้ callback ที่ซับซ้อนพร้อมหลายเมธอดเหตุการณ์ที่หลายคนสนใจ closure ง่ายๆ ที่มี 1-2 callback

Delegate เหมาะสมที่สุดเมื่อคุณต้องการส่งชุดเหตุการณ์ที่เกี่ยวข้องไปยังผู้รับรายเดียว NotificationCenter เหมาะสำหรับการแจ้งเตือนแบบกระจายเสียง Closure สำหรับการดำเนินการแบบอะซิงโครนัสอย่างง่าย เช่น completion handler ใน URLSession

การนำ Delegate ไปใช้ใน Objective-C

Objective-C ใช้ @protocol และ @optional สำหรับการประกาศดีลิเกต ต่างจาก Swift เมธอดโปรโตคอลทั้งหมดเป็นแบบเลือกได้โดยค่าเริ่มต้น ความแตกต่างหลักคือการเรียก respondsToSelector: ก่อนส่งข้อความไปยังดีลิเกต เนื่องจากเมธอดอาจไม่ได้ถูกนำไปใช้

Objective-C
@protocol ImageCacheDelegate 
@optional
- (void)cacheDidStartDownload: (ImageCache *)cache;
- (void)cache: (ImageCache *)cache didCacheImage: (UIImage *)image;
@required
- (void)cache: (ImageCache *)cache didFailWithError: (NSError *)error;
@end

@interface ImageCache : NSObject
@property (nonatomic, weak) id<ImageCacheDelegate> delegate;
- (void)downloadImageAtURL: (NSURL *)url;
@end

@implementation ImageCache
- (void)downloadImageAtURL: (NSURL *)url {
    if ([self.delegate respondsToSelector:@selector(cacheDidStartDownload:)]) {
        [self.delegate cacheDidStartDownload:self];
    }
    // การโหลดรูปภาพแบบอะซิงโครนัส
}
@end

ความแตกต่างหลักใน Objective-C: ก่อนเรียกเมธอดแบบเลือกได้ จำเป็นต้องมีการตรวจสอบ respondsToSelector: ใน Swift เมธอดโปรโตคอลแบบเลือกได้จะขจัดการตรวจสอบนี้ — optional chaining (?.) จัดการกรณีที่ไม่มีการนำไปใช้โดยอัตโนมัติ

ข้อผิดพลาดทั่วไปเมื่อทำงานกับดีลิเกต

ข้อผิดพลาดในการใช้ดีลิเกต นำไปสู่หน่วยความจำรั่ว แอปพลิเคชันดับ และบักที่ซ่อนเร้น มาดูปัญหาที่พบบ่อยที่สุดห้าประการ

การอ้างอิงแบบแข็งไปยังดีลิเกต

Retain cycle เป็นข้อผิดพลาดที่พบบ่อยที่สุด หากคุณสมบัติ delegate ถูกประกาศเป็น strong และดีลิเกตก็เป็นเจ้าของออบเจกต์เจ้าของด้วย จะเกิดวงจรการคงอยู่ขึ้น ออบเจกต์ทั้งสองจะไม่มีวันถูกปลดปล่อยจากหน่วยความจำ วิธีแก้: ประกาศดีลิเกตเป็น weak var ใน Swift หรือ @property (weak) ใน Objective-C เสมอ

ดีลิเกตไม่ถูกล้างหลัง dealloc

หากออบเจกต์เจ้าของมีอายุยืนกว่าดีลิเกตและการอ้างอิงยังคงอยู่ การเรียกเมธอดดีลิเกตจะส่งผลให้เกิด EXC_BAD_ACCESS การอ้างอิงแบบอ่อนแก้ปัญหานี้โดยอัตโนมัติ: หลังจากดีลิเกตถูกปลดปล่อย คุณสมบัติจะกลายเป็น nil อย่างไรก็ตาม ในสถานการณ์แบบหลายเธรด คุณควรตรวจสอบดีลิเกตเพิ่มเติมในเธรดหลัก

จำนวนเมธอดที่มากเกินไปในโปรโตคอล

โปรโตคอลที่มีเมธอดมากกว่า 20 รายการละเมิดหลักการแยกอินเทอร์เฟซ (ISP) UITableViewDelegate มีเมธอดแบบเลือกได้ประมาณ 30 รายการ — นี่เป็นข้อยกเว้นทางประวัติศาสตร์ ในโปรโตคอลของคุณเอง ควรแบ่งความรับผิดชอบออกเป็นโปรโตคอลย่อยหลายๆ โปรโตคอล แต่ละโปรโตคอลมีบทบาทของตัวเอง

ตัวอย่าง Delegate ใน API ระบบ iOS

API ระบบของ Apple ใช้รูปแบบ Delegate อย่างจริงจัง มาดูตัวอย่างสำคัญสามตัวอย่างจาก UIKit ที่ปรากฏในทุกแอปพลิเคชัน iOS

APIโปรโตคอลเมธอดหลัก
UITableViewUITableViewDelegatedidSelectRowAt, heightForRowAt, willDisplay
UITextFieldUITextFieldDelegateshouldChangeCharactersIn, didBeginEditing, shouldReturn
URLSessionURLSessionDelegatedidReceiveChallenge, didCompleteWithError, didBecomeInvalidWithError

แต่ละโปรโตคอลเหล่านี้นำพฤติกรรมในแง่มุมต่างๆ ไปใช้: UITableViewDelegate จัดการรูปลักษณ์และการตอบสนองต่อการสัมผัส UITextFieldDelegate ควบคุมการป้อนข้อความ URLSessionDelegate จัดการเหตุการณ์เครือข่าย สิ่งนี้แสดงให้เห็นถึงความยืดหยุ่นของรูปแบบ: ดีลิเกตสามารถปรับให้เข้ากับพื้นที่ความรับผิดชอบใดๆ

คำถามที่พบบ่อย

ความแตกต่างระหว่าง delegate และ dataSource ใน iOS คืออะไร?

Delegate จัดการพฤติกรรมและรูปลักษณ์ (ความสูงของเซลล์ การตอบสนองต่อการสัมผัส) DataSource ให้ข้อมูล (จำนวนแถว เนื้อหาของเซลล์) ใน UITableViewDelegate และ UITableViewDataSource — เป็นโปรโตคอลสองรายการที่แยกจากกันซึ่งแบ่งความรับผิดชอบระหว่างการนำเสนอและข้อมูล

ทำไม delegate ถึงถูกประกาศเป็น weak?

การอ้างอิงแบบอ่อน ป้องกัน retain cycle เจ้าของ (เช่น UITableView) เก็บการอ้างอิงไปยังดีลิเกตเป็น weak เท่านั้น หากดีลิเกต (UIViewController) เป็นเจ้าของตาราง การอ้างอิงแบบแข็งไปยังดีลิเกตจะสร้างวงจร: ViewController → UITableView → Delegate (ViewController) Weak ทำลายวงจรนี้

สามารถใช้ delegate ใน SwiftUI ได้หรือไม่?

ใน SwiftUI รูปแบบ Delegate ถูกใช้น้อยลง — มันถูกแทนที่ด้วย @Binding, @State และ closure อย่างไรก็ตาม ดีลิเกตยังคงใช้สำหรับการรวม UIKit ผ่าน UIViewRepresentable ตัวอย่างเช่น MKMapViewDelegate และ WKUIDelegate ยังคงมีความเกี่ยวข้องเมื่อห่อหุ้มส่วนประกอบ UIKit ใน SwiftUI

@objc optional ในโปรโตคอล Swift คืออะไร?

@objc optional อนุญาตให้ประกาศเมธอดแบบเลือกได้ในโปรโตคอล Swift นี่คือกลไกความเข้ากันได้กับรันไทม์ Objective-C หากไม่มี @objc เมธอดโปรโตคอล Swift ทั้งหมดจะบังคับโดยค่าเริ่มต้น Optional ใช้ในโปรโตคอล UIKit ที่ดีลิเกตสามารถนำไปใช้เฉพาะเมธอดที่ต้องการเท่านั้น

หนึ่งออบเจกต์สามารถมีดีลิเกตได้กี่ตัว?

หนึ่งออบเจกต์สามารถมี ดีลิเกตเพียงตัวเดียว สำหรับแต่ละคุณสมบัติ delegate หากคุณต้องแจ้งให้หลายออบเจกต์ทราบ ให้ใช้ multicast delegate, อาร์เรย์ของดีลิเกต หรือ NotificationCenter รูปแบบ Delegate ถูกออกแบบมาให้เป็นความสัมพันธ์แบบ 1:1

สรุป

  • Delegate — รูปแบบการออกแบบเชิงพฤติกรรมที่ถ่ายโอนการทำงานจากออบเจกต์หนึ่งไปยังอีกออบเจกต์หนึ่งผ่านโปรโตคอล
  • โปรโตคอล Swift ประกาศชุดของเมธอด; เมธอดแบบเลือกได้ถูกทำเครื่องหมายด้วย @objc optional, เมธอดแบบบังคับถูกนำไปใช้เสมอ
  • การอ้างอิงแบบอ่อน ไปยังดีลิเกตจำเป็นเพื่อป้องกัน retain cycle และหน่วยความจำรั่ว
  • UITableViewDelegate เป็นตัวอย่างที่รู้จักกันดีที่สุด; เมธอดของมันจัดการความสูงของเซลล์ การเลือก และการแสดงผล
  • Delegate แตกต่างจาก NotificationCenter ด้วยความสัมพันธ์แบบ 1:1 เทียบกับ 1:N และความปลอดภัยของชนิดที่สมบูรณ์
  • Objective-C ต้องการการตรวจสอบ respondsToSelector: สำหรับเมธอดแบบเลือกได้ Swift จัดการสิ่งนี้โดยอัตโนมัติ
  • คำแนะนำ: ใช้ delegate สำหรับ callback ที่ซับซ้อนพร้อมหลายเมธอดที่เกี่ยวข้อง และใช้ closure สำหรับ closure อย่างง่าย

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม