objective-c - ويكيبيديا - ما هو البروتوكول




تحديد فئات البروتوكولات في الهدف ج؟ (5)

في Objective-C ، يمكنني إضافة طرق إلى الفئات الموجودة مع فئة ، على سبيل المثال

@interface NSString (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

هل من الممكن أيضًا القيام بذلك مع البروتوكولات ، أي إذا كان هناك بروتوكول NSString ، مثل:

@interface <NSString> (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

أريد أن أفعل ذلك لأن لدي عدة امتدادات لـ NSObject (الفئة) ، باستخدام طرق NSObject العامة فقط ، وأريد أن تعمل هذه الملحقات أيضًا مع الكائنات التي تنفذ البروتوكول.

لإعطاء مثال إضافي ، ماذا لو كنت أرغب في كتابة logDescription للأسلوب الذي يطبع وصف كائن إلى السجل:

- (void) logDescription {
    NSLog(@"%@", [self description]);
}

يمكنني بالطبع إضافة هذه الطريقة إلى NSObject ، ولكن هناك فئات أخرى لا ترث من NSObject ، حيث أرغب أيضًا في الحصول على هذه الطريقة ، مثل NSProxy. نظرًا لأن الأسلوب لا يستخدم سوى أعضاء البروتوكول العام ، فمن الأفضل إضافته إلى البروتوكول.

تحرير: يحتوي Java 8 الآن على "طرق تمديد افتراضية" في الواجهات: http://cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf . هذا هو بالضبط ما أود القيام به في الهدف جيم. لم أكن أرى هذا السؤال يثير الكثير من الاهتمام ...

التحيات ، يوتشن


أعتقد أنك قد تخلط بين المصطلحات هنا وهناك. الإضافات والفئات والبروتوكولات والواجهات والفئات كلها أشياء مختلفة في الهدف ج. في Objective-C 2.0 Language ، تصف Apple الاختلافات جيدًا ، بما في ذلك مزايا وعيوب استخدام الفئات والإضافات.

إذا فكرت في الأمر ، فما هو "الفئة" أو "الامتداد" بالمعنى المفاهيمي؟ إنها وسيلة لإضافة وظائف إلى الفصل. في الهدف- C ، تم تصميم البروتوكولات بحيث لا يكون لها أي تنفيذ. لذلك ، كيف يمكنك إضافة أو تمديد تنفيذ شيء لا يوجد به تطبيق لتبدأ؟


إجابة قصيرة: رقم

إجابة طويلة: كيف سيكون هذا العمل؟ تخيل أنك تستطيع إضافة طرق إلى البروتوكولات الحالية؟ كيف سيكون هذا العمل؟ تخيل أننا أردنا إضافة طريقة أخرى إلى NSCoding ، قل -(NSArray *) codingKeys; هذه الطريقة هي طريقة مطلوبة تقوم بإرجاع مجموعة من المفاتيح المستخدمة لتشفير الكائن.

المشكلة هي أن هناك فئات موجودة (مثل NSString مثلاً) تقوم بالفعل بتنفيذ NSCoding ، لكن لا تطبق طريقة codingKeys بنا. ما ينبغي أن يحدث؟ كيف يمكن لإطار العمل المترجم مسبقًا أن يعرف ماذا يفعل عندما يتم إرسال هذه الرسالة المطلوبة إلى فصل لا ينفذها؟

يمكنك أن تقول "يمكننا إضافة تعريف هذه الطريقة عن طريق فئة" أو "يمكننا القول أن أي طرق تمت إضافتها عبر فئات البروتوكول هذه اختيارية صراحة". نعم ، يمكنك فعل ذلك والتغلب على المشكلة التي وصفتها أعلاه نظريًا. ولكن إذا كنت ستقوم بذلك ، فيمكنك أيضًا جعلها فئة في المقام الأول ، ثم تحقق للتأكد من respondsToSelector: الفصل respondsToSelector: قبل استخدام الطريقة.


على الرغم من أنه لا يمكنك تحديد فئات للبروتوكولات (ولن ترغب في ذلك ، لأنك لا تعرف شيئًا عن الكائن الموجود) ، يمكنك تعريف الفئات بطريقة تنطبق عليها الكود فقط النوع المحدد الذي يحتوي على البروتوكول المرغوب (نوع من التخصص الجزئي لقوالب C ++).

الاستخدام الرئيسي لشيء من هذا القبيل هو عندما ترغب في تحديد فئة تعتمد على نسخة مخصصة من الفصل. (تخيل أن لديّ فئات فرعية لـ UIViewController تتوافق مع بروتوكول Foo ، مما يعني أن لديهم خاصية foo ، وقد يكون رمز الفئة الخاص بي بحاجة إلى خاصية foo ، لكن لا يمكنني تطبيقها على بروتوكول Foo ، وإذا كنت ببساطة أطبقها إلى UIViewController ، لن يتم تجميع الشفرة افتراضيًا ، وإجبارها على الترجمة يعني أن أي شخص يقوم بالتأمل ، أو مجرد حل مشكلة ، قد يتصل بالرمز الذي يعتمد على البروتوكول. يمكن أن تعمل الطريقة المختلطة مثل هذا:

@protocol Foo
- (void)fooMethod

@property (retain) NSString *foo;
@end

@implementation UIViewController (FooCategory)

- (void)fooMethod {
    if (![self conformsToProtocol:@protocol(Foo)]) {
        return;
    }

    UIViewController<Foo> *me = (UIViewController<Foo>*) self;
    // For the rest of the method, use "me" instead of "self"
    NSLog(@"My foo property is \"%@\"", me.foo);
}
@end

باستخدام النهج المختلط ، يمكنك كتابة الرمز مرة واحدة فقط (لكل فئة يفترض أن تنفذ البروتوكول) وتأكد من أنها لن تؤثر على مثيلات الفئة التي لا تتوافق مع البروتوكول.

الجانب السلبي هو أن توليف / تعريف الخاصية لا يزال يجب أن يحدث في الفئات الفرعية الفردية.


ليس من المجدي فعل ذلك فعلاً لأن البروتوكول لا يمكنه بالفعل تنفيذ هذه الطريقة. البروتوكول هو وسيلة لإعلان أنك تدعم بعض الأساليب. تعني إضافة طريقة إلى هذه القائمة خارج البروتوكول أن جميع فئات "المطابقة" تعلن بطريق الخطأ عن الطريقة الجديدة على الرغم من أنها لا تنفذها. إذا نفذت فئة ما بروتوكول NSObject لكن لم تنزل من NSObject ، ثم قمت بإضافة طريقة إلى البروتوكول ، فإن ذلك سيؤدي إلى كسر توافق الفئة.

ومع ذلك ، يمكنك إنشاء بروتوكول جديد يتضمن البروتوكول القديم بإعلان مثل @protocol SpecialObject <NSObject> .


نشر آدم شارب الحل الذي يعمل بالنسبة لي.

يتضمن 3 خطوات:

  1. تحديد الطرق التي تريد إضافتها كـ @optional على بروتوكول.
  2. جعل الكائنات التي تريد تمديدها تتوافق مع هذا البروتوكول.
  3. نسخ هذه الأساليب إلى تلك الكائنات في وقت التشغيل.

تحقق من الرابط للحصول على التفاصيل الكاملة.







categories