Protocol هو مجموعة من المتطلبات (الخصائص والطرق) التي يجب أن يفي بها النوع الذي يتبنى البروتوكول. في Swift، البروتوكولات هي العنصر المركزي في البرمجة الموجهة بالبروتوكولات (POP)، مما يتيح تعدد الأشكال دون وراثة. وفقًا لـ Swift.org (2025)، تُستخدم البروتوكولات في 85% من أنواع المكتبة القياسية لـ Swift. في Objective-C، يؤدي @protocol دورًا مشابهًا، ولكن مع قيد — فقط للفئات.
الخلاصة
Protocol في Swift هو واجهة مجردة تحدد المتطلبات التي يجب أن يفي بها النوع. يمكن للبروتوكول أن يطلب خصائص (مع getter/setter)، وطرق (للنسخة وللنوع)، ومهيئات، ومخطوطات فرعية. على عكس الفئات، يمكن تبني البروتوكولات بواسطة البنى والتعدادات والفئات — مما يوفر مرونة غير متوفرة في اللغات القائمة على الفئات فقط.
protocol Drawable {
var boundingRect: CGRect { get }
mutating func draw(in context: CGContext)
}
struct Circle: Drawable {
var center: CGPoint
var radius: CGFloat
var boundingRect: CGRect {
CGRect(x: center.x - radius, y: center.y - radius,
width: radius * 2, height: radius * 2)
}
func draw(in context: CGContext) {
context.addEllipse(in: boundingRect)
}
}البنية Circle تتبنى بروتوكول Drawable، موفرة الخاصية boundingRect والطريقة draw(in:). بفضل البروتوكول، يمكن معالجة أي شكل يطبق Drawable بشكل موحد — هذا هو تعدد الأشكال دون وراثة من فئة أساسية مشتركة.
البرمجة الموجهة بالبروتوكولات (POP) هي نموذج قدمته Apple في WWDC 2015 كبديل للوراثة القائمة على الفئات. في POP، البروتوكولات هي أداة التجريد الرئيسية وامتدادات البروتوكول توفر تطبيقات افتراضية. هذا يحل مشكلة «وراثة الماس» ويسمح بتوسيع الأنواع الموجودة دون تعديل الكود المصدري.
| الجانب | POP (موجه بالبروتوكولات) | OOP (قائم على الفئات) |
|---|---|---|
| وحدة التجريد | Protocol | فئة أساسية |
| آلية إعادة الاستخدام | امتداد البروتوكول | الوراثة |
| أنواع القيمة | مدعومة (struct) | أنواع المرجع فقط |
| التبني المتعدد | تكوين البروتوكول | الوراثة المتعددة (ليس في Swift) |
| خطر الاقتران | منخفض (اقتران ضعيف) | مرتفع (تسلسل هرمي صلب) |
وفقًا لمدونة Apple Swift (2025)، تشكل البنى 70% من الأنواع في تطبيقات Swift الحديثة. POP هو سبب رئيسي لهذا التحول: البروتوكولات تسمح للبنى بالحصول على سلوك متعدد الأشكال دون الانتقال إلى الفئات.
بروتوكولات Swift تحتل موقعًا وسطًا بين واجهات Java والفئات المجردة في C++. يمكنها احتواء تطبيقات (عبر الامتدادات) لكن لا يمكنها امتلاك حالة (خصائص مخزنة). دعنا نفحص الاختلافات عبر ثلاث لغات.
| الخاصية | Swift Protocol | Java Interface | C++ Abstract Class |
|---|---|---|---|
| تطبيق الطرق | نعم (extension) | نعم (طرق افتراضية) | نعم |
| خصائص مخزنة | لا | لا | نعم |
| أنواع القيمة | نعم | لا | لا |
| تطبيق متعدد | نعم | نعم | نعم |
| مهيئات | نعم (متطلبات) | لا | نعم |
الفرق الرئيسي: Swift Protocol يمكنه طلب مهيئات ومخطوطات فرعية، وهو غير متوفر في Java Interface. ومع ذلك، لا يمكن للبروتوكول تخزين حالة — وهذا يبقى مسؤولية النوع الذي يتبنى البروتوكول.
النوع المرتبط (Associated Type) هو نوع عام داخل بروتوكول يتم تجسيده بواسطة النوع المتبني. هذا يسمح بإنشاء بروتوكولات آمنة النوع دون تحديد نوع بيانات محدد. تعمل الأنواع المرتبطة جنبًا إلى جنب مع الأدوية العامة في Swift.
protocol Container {
associatedtype Item
var count: Int { get }
mutating func append(_ item: Item)
subscript(i: Int) -> Item { get }
}
struct IntStack: Container {
var items: [Int] = []
var count: Int { items.count }
typealias Item = Int
mutating func append(_ item: Int) {
items.append(item)
}
subscript(i: Int) -> Int {
items[i]
}
}
func sum<C: Container>(_ container: C) -> C.Item where C.Item: Numeric {
// جسم الدالة
}Container هو بروتوكول مع associatedtype Item. IntStack يطبقه بتحديد typealias Item = Int. الدالة العامة sum تستخدم جملة where للعمل فقط مع الحاويات الرقمية. الأنواع المرتبطة تجعل البروتوكولات عامة دون فقدان أمان النوع.
تكوين البروتوكول — دمج عدة بروتوكولات عبر عامل التشغيل &. النوع المتوافق مع التكوين يجب أن ينفذ جميع البروتوكولات المدمجة. هذا يستبدل الوراثة المتعددة، الغائبة في Swift، ويسمح بتحديد دقيق لمتطلبات معاملات الدوال.
protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }
struct Person: Named, Aged {
let name: String
let age: Int
}
func greet(_ entity: Named & Aged) {
print("مرحبًا، \(entity.name)، العمر \(entity.age)!")
}
// امتداد البروتوكول — تطبيق افتراضي
extension Named {
func introduce() {
print("اسمي \(name)")
}
}امتداد البروتوكول يوفر تطبيقات افتراضية للطرق. النوع الذي يتبنى البروتوكول يمكنه تجاوز طريقة الامتداد — في هذه الحالة، يتم استدعاء تطبيقه الخاص. هذه هي الآلية التي ينفذ بها Swift الطرق الاختيارية دون @objc.
@protocol في Objective-C هو سلف Swift Protocol، ولكن مع قيود كبيرة. بروتوكولات Objective-C متاحة فقط للفئات (ليس للبنى أو التعدادات) وتستخدم الإرسال الديناميكي عبر تمرير الرسائل. يمكن أن تكون الطرق @required (افتراضيًا) أو @optional.
@protocol Loggable
@required
- (void)logMessage: (NSString *)message;
@optional
- (NSString *)logPrefix;
@end
@interface ConsoleLogger : NSObject
@end
@implementation ConsoleLogger
- (void)logMessage: (NSString *)message {
NSLog(@"[LOG] %@", message);
}
@endعلى عكس Swift، بروتوكولات Objective-C لا تدعم الأنواع المرتبطة أو الأدوية العامة أو امتدادات البروتوكول أو أنواع القيمة. تبقى آلية تجريد قائمة على الفئات، بينما Swift Protocol هي أداة تعدد أشكال كاملة لجميع الأنواع.
الأسئلة الشائعة
البروتوكول لا يمكنه تخزين حالة (خصائص مخزنة) — فقط متطلبات الخصائص. الفئة المجردة يمكنها احتواء حقول بيانات. البروتوكول يمكن تبنيه بواسطة البنى والتعدادات، بينما الفئة المجردة يمكن توريثها فقط بواسطة الفئات. في Swift، البروتوكولات هي أداة التجريد الرئيسية؛ الفئات تستخدم بشكل أقل.
POP هو نموذج حيث تحل البروتوكولات وامتدادات البروتوكول محل التسلسلات الهرمية العميقة للوراثة. بدلاً من فئة أساسية ترث منها جميع الفئات الفرعية، يستخدم POP تكوين البروتوكولات مع تطبيقات افتراضية عبر الامتداد. هذا يقلل الاقتران ويحسن إعادة استخدام الكود.
نعم، بروتوكولات Swift تدعم الوراثة. protocol SerializableDrawable: Drawable, Codable — بروتوكول يجمع متطلبات Drawable و Codable. النوع الذي يتبنى SerializableDrawable يجب أن يفي بمتطلبات جميع البروتوكولات في التسلسل الهرمي. هذا يختلف عن وراثة الفئات — البروتوكولات ليس لها سلف مشترك.
some (نوع معتم) يضمن أن الدالة ترجع نوعًا واحدًا محددًا يتوافق مع البروتوكول. any (نوع وجودي) يسمح بتخزين أي نوع يتوافق مع البروتوكول. some يستخدم للحفاظ على هوية النوع، any — للمجموعات غير المتجانسة. some ظهر في Swift 5.1، any — في Swift 5.7.
استخدم is للتحقق و as? للتحويل: if let drawable = object as? Drawable { drawable.draw(in: ctx) }. في Objective-C يُستخدم conformsToProtocol:. Swift يدعم أيضًا التحقق is للبروتوكولات بدون أنواع مرتبطة.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا