Protocol trong Swift là một hợp đồng xác định một tập các yêu cầu mà bất kỳ kiểu nào chấp nhận nó phải đáp ứng. Các giao thức là nền tảng của Lập trình Hướng Giao thức (POP) — một mô hình được Apple khuyến nghị cho Swift cùng với OOP cổ điển. Theo Apple Documentation, 2026, các cấu trúc, lớp và enum có thể chấp nhận giao thức, làm cho kiến trúc trở nên linh hoạt và có thể kiểm thử.
Các điểm chính
Protocol là một giao diện trừu tượng xác định một kiểu phải có khả năng làm gì, nhưng không phải làm như thế nào. Trong Swift, một giao thức tương tự như các interface trong Java hoặc Go, nhưng với các khả năng bổ sung.
Một giao thức có thể yêu cầu:
{ get } hoặc { get set }Theo WWDC 2015, Apple đã giới thiệu Lập trình Hướng Giao thức như một cách tiếp cận cơ bản cho kiến trúc ứng dụng Swift. Không giống như OOP, nơi kế thừa lớp tạo ra các hệ thống phân cấp cứng nhắc, POP cung cấp sự kết hợp giao thức. Điều này mang lại sự linh hoạt: một kiểu duy nhất có thể tuân thủ nhiều giao thức, nhận các yêu cầu và triển khai của chúng thông qua các phần mở rộng.
Protocol được khai báo với từ khóa protocol, tên và phần thân.
protocol Drawable {
func draw(context: CGContext)
var boundingBox: CGRect { get }
}
Một kiểu chấp nhận giao thức bằng cách sử dụng dấu hai chấm sau tên của nó:
struct Circle: Drawable {
let center: CGPoint
let radius: CGFloat
func draw(context: CGContext) {
context.addArc(center: center, radius: radius, ...)
}
var boundingBox: CGRect {
CGRect(x: center.x - radius, y: center.y - radius,
width: radius * 2, height: radius * 2)
}
}
Một kiểu duy nhất có thể chấp nhận nhiều giao thức phân cách bằng dấu phẩy: struct MyType: ProtocolA, ProtocolB. Trình biên dịch kiểm tra rằng tất cả các yêu cầu của mỗi giao thức được đáp ứng.
Yêu cầu về thuộc tính được khai báo với từ khóa var và các bộ chỉ định truy cập { get } hoặc { get set }.
protocol UserProtocol {
var name: String { get }
var age: Int { get set }
static var maxAge: Int { get }
mutating func updateName(_ newName: String)
}
Từ khóa mutating trong một giao thức cho biết phương thức có thể sửa đổi self. Các cấu trúc phải triển khai phương thức đó như mutating, trong khi các lớp có thể bỏ qua nó. Yêu cầu về phương thức được khai báo với chữ ký đầy đủ, bao gồm cả nhãn tham số.
Protocol có thể kế thừa một giao thức khác, thêm các yêu cầu mới. Điều này tạo ra một hệ thống phân cấp các hợp đồng mà không có sự ràng buộc chặt chẽ với lớp.
protocol Vehicle {
var speed: Double { get set }
func move()
}
protocol Flyable: Vehicle {
var altitude: Double { get set }
func takeOff()
}
Một kiểu chấp nhận Flyable phải đáp ứng các yêu cầu của cả hai giao thức — Vehicle và Flyable. Swift hỗ trợ đa kế thừa giao thức: protocol A: B, C.
Protocol Composition là một cơ chế cho phép chỉ định rằng một kiểu phải tuân thủ đồng thời nhiều giao thức, mà không cần tạo một giao thức kết hợp mới.
func render(_ item: Drawable & Animatable) {
item.draw(context: ...)
item.animate(duration: 0.3)
}
Sự kết hợp (&) hoạt động trong các tham số hàm, biến và ràng buộc generic. Trình biên dịch kiểm tra rằng kiểu được truyền vào đồng thời đáp ứng tất cả các giao thức. Sự kết hợp được sử dụng rộng rãi trong SwiftUI: some View là một generic với sự kết hợp.
Protocol Composition được ưu tiên hơn việc tạo hệ thống phân cấp kế thừa: thay vì protocol A: B, C, có thể chấp nhận trực tiếp B & C. Điều này mang lại sự linh hoạt và giảm sự ràng buộc. Sự kết hợp đặc biệt hữu ích trong các tham số hàm và ràng buộc generic nơi cần kết hợp tạm thời các yêu cầu mà không tạo giao thức trung gian. Điều này giảm số lượng kiểu phụ trợ trong mã.
Protocol có thể được sử dụng như kiểu của một biến, tham số hàm hoặc phần tử tập hợp. Điều này được gọi là kiểu existential.
var drawableItem: Drawable
let items: [Drawable] = [Circle(...), Rectangle(...)]
func process(drawables: [any Drawable]) {
for item in drawables {
item.draw(context: ...)
}
}
Từ khóa any (Swift 5.6+) đánh dấu rõ ràng một existential. Nếu không có any, trình biên dịch sẽ đưa ra cảnh báo. Swift cũng hỗ trợ some (kiểu opaque) để ẩn kiểu cụ thể đằng sau một giao thức — đây là cách tiếp cận tiêu chuẩn trong SwiftUI.
Khi làm việc với giao thức, các nhà phát triển thường mắc phải một số lỗi lặp đi lặp lại.
Drawable thay vì <T: Drawable> ở nơi cần kiểu cụ thểAnyObject không cần thiết, loại trừ struct và enumCâu hỏi thường gặp
Protocol chỉ xác định các yêu cầu mà không có triển khai (cho đến khi có protocol extensions). Abstract class có thể chứa triển khai và trạng thái. Swift không có lớp trừu tượng — vai trò của chúng được thực hiện bởi các giao thức với phần mở rộng.
Có, cấu trúc, lớp và enum đều có thể chấp nhận giao thức. Đây là nền tảng của POP: bạn không bắt buộc phải sử dụng lớp để tổ chức kiến trúc. Các cấu trúc với giao thức cung cấp ngữ nghĩa giá trị và tính bất biến.
Kiểu liên kết (associatedtype) là một chỗ dành cho kiểu mà kiểu triển khai tự xác định. Ví dụ: Collection có associatedtype Element. Đây là một generic ở cấp độ giao thức.
Có, thêm kế thừa từ AnyObject: protocol MyProtocol: AnyObject. Khi đó chỉ có lớp mới có thể chấp nhận giao thức này. Điều này hữu ích cho các tham chiếu yếu và ủy quyền.
Sử dụng is để kiểm tra và as? để ép kiểu: if let drawable = item as? Drawable. Điều này chỉ hoạt động với các giao thức không có kiểu liên kết.
Tổng kết
&) kết hợp các giao thức mà không cần kế thừaany) và kiểu opaque (some) — hai cách làm việc với giao thứcChúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm