Protocol في Swift هو عقد يحدد مجموعة من المتطلبات التي يجب أن يفي بها أي نوع يتبناه. تشكل البروتوكولات أساس البرمجة الموجهة بالبروتوكولات (POP) — وهي نموذج أوصت به Apple لـ Swift إلى جانب OOP التقليدية. وفقاً لـ Apple Documentation, 2026، يمكن للهياكل والفئات والتعدادات تبنّي البروتوكولات، مما يجعل البنية مرنة وقابلة للاختبار.
أهم النقاط
Protocol هو واجهة مجردة تحدد ما يجب أن يكون النوع قادراً على فعله، ولكن ليس كيف يفعله. في Swift، البروتوكول مشابه للواجهات في Java أو Go، لكن مع إمكانيات إضافية.
يمكن للبروتوكول أن يطلب:
{ get } أو { get set }وفقاً لـ WWDC 2015، قدمت Apple البرمجة الموجهة بالبروتوكولات كنهج أساسي لهندسة تطبيقات Swift. على عكس OOP حيث تخلق وراثة الفئات تسلسلات هرمية صلبة، تقدم POP تركيب البروتوكولات. وهذا يوفر مرونة: يمكن لنوع واحد أن يتوافق مع بروتوكولات متعددة، ويحصل على متطلباتها وتطبيقاتها من خلال الامتدادات.
Protocol يُعرّف بالكلمة المفتاحية protocol واسم وجسم.
protocol Drawable {
func draw(context: CGContext)
var boundingBox: CGRect { get }
}
يتبنى النوع بروتوكولاً باستخدام نقطتين بعد اسمه:
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)
}
}
يمكن لنوع واحد أن يتبنى بروتوكولات متعددة مفصولة بفواصل: struct MyType: ProtocolA, ProtocolB. يتحقق المترجم من استيفاء جميع متطلبات كل بروتوكول.
متطلبات الخصائص تُعلن بالكلمة المفتاحية var ومحددات الوصول { get } أو { get set }.
protocol UserProtocol {
var name: String { get }
var age: Int { get set }
static var maxAge: Int { get }
mutating func updateName(_ newName: String)
}
الكلمة المفتاحية mutating في البروتوكول تعني أن الدالة يمكنها تعديل self. يجب على الهياكل تنفيذ هذه الدالة بصفتها mutating، بينما يمكن للفئات حذفها. متطلبات الدوال تُعلن بتوقيع كامل يشمل تسميات المعاملات.
Protocol يمكنه توريث بروتوكول آخر، مضيفاً متطلبات جديدة. وهذا يخلق تسلسلاً هرمياً من العقود دون ارتباط صارم بالفئات.
protocol Vehicle {
var speed: Double { get set }
func move()
}
protocol Flyable: Vehicle {
var altitude: Double { get set }
func takeOff()
}
النوع الذي يتبنى Flyable يجب أن يفي بمتطلبات كلا البروتوكولين — Vehicle و Flyable. Swift يدعم التوريث المتعدد للبروتوكولات: protocol A: B, C.
Protocol Composition هي آلية تتيح تحديد أن نوعاً ما يجب أن يتوافق مع بروتوكولات متعددة في وقت واحد، دون إنشاء بروتوكول جديد مُركّب.
func render(_ item: Drawable & Animatable) {
item.draw(context: ...)
item.animate(duration: 0.3)
}
التركيب (&) يعمل في معاملات الدوال والمتغيرات والقيود العامة. يتحقق المترجم من أن النوع المُمرر في وقت واحد يلبي جميع البروتوكولات. يُستخدم التركيب على نطاق واسع في SwiftUI: some View هو نوع عام مع تركيب.
Protocol Composition أفضل من إنشاء تسلسل هرمي للوراثة: بدلاً من protocol A: B, C يمكن تبنّي B & C مباشرة. وهذا يوفر مرونة ويقلل الاقتران. التركيب مفيد بشكل خاص في معاملات الدوال والقيود العامة حيث تحتاج إلى دمج المتطلبات مؤقتاً دون إنشاء بروتوكول وسيط. وهذا يقلل عدد الأنواع المساعدة في الكود.
Protocol يمكن استخدامه كنوع لمتغير أو معامل دالة أو عنصر مجموعة. وهذا يُسمى النمط الوجودي.
var drawableItem: Drawable
let items: [Drawable] = [Circle(...), Rectangle(...)]
func process(drawables: [any Drawable]) {
for item in drawables {
item.draw(context: ...)
}
}
الكلمة المفتاحية any (Swift 5.6+) تُحدد صراحة النمط الوجودي. بدون any، يُصدر المترجم تحذيراً. Swift يدعم أيضاً some (الأنواع غير الشفافة) لإخفاء النوع الملموس خلف بروتوكول — وهذا نهج قياسي في SwiftUI.
عند العمل مع البروتوكولات، يرتكب المطورون غالباً عدة أخطاء متكررة.
Drawable بدلاً من <T: Drawable> حيث نحتاج نوعاً ملموساًAnyObject دون داعٍ مما يستثني الهياكل والتعداداتالأسئلة الشائعة
Protocol يُحدد فقط المتطلبات دون تطبيق (حتى ظهور protocol extensions). الـ abstract class يمكن أن يحتوي على تطبيق وحالة. لا توجد فئات مجردة في Swift — دورها تؤديه البروتوكولات مع الامتدادات.
نعم، الهياكل والفئات والتعدادات — جميعها يمكنها تبنّي البروتوكولات. هذا أساس POP: لست مضطراً لاستخدام الفئات لتنظيم البنية. الهياكل مع البروتوكولات توفر دلالات القيم والثبات.
Associated type (associatedtype) هو عنصر نائب لنوع يحدده النوع المنفذ بنفسه. مثال: Collection لديه associatedtype Element. هذا نوع عام على مستوى البروتوكول.
نعم، أضف وراثة من AnyObject: protocol MyProtocol: AnyObject. عندها فقط الفئات ستتمكن من تبنّي هذا البروتوكول. هذا مفيد للمراجع الضعيفة والمفوّضين.
استخدم is للتحقق و as? للتحويل: if let drawable = item as? Drawable. هذا يعمل فقط مع البروتوكولات التي ليس لها أنواع مرتبطة.
الخلاصة
&) يجمع البروتوكولات دون وراثةany) و الأنواع غير الشفافة (some) — طريقتان للعمل مع البروتوكولاتسنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.