English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

ملخص وتحليل الاختلافات بين KVC،KVO،NSNotification،delegate في iOS

ملخص وتحليل الاختلافات بين KVC،KVO،NSNotification،delegate في iOS

 1、KVC، أي protocol غير رسمي يُدعى NSKeyValueCoding، يوفر آلية للوصول إلى خصائص الأجسام بشكل غير مباشر. وليس عن طريق دعوة طرق Setter و Getter. KVO هي واحدة من التقنيات الأساسية التي تنفذ على أساس KVC.

Demo:

@interface myPerson : NSObject
{  
    NSString*_name;  
    int   _age;  
    int   _height;  
    int   _weight;
}
@interface testViewController :UIViewController 
@property (nonatomic, retain) myPerson*testPerson; 
@end
- (void)testKVC;
{  
testPerson = [[myPerson alloc] init];    
 NSLog(@"testPerson's init height =%@", [testPerson valueForKey:@"height"]);  
[testPerson setValue:[NSNumber numberWithInt:168]forKey:@"height"]; NSLog(@"testPerson’s height = %@", [testPerson valueForKey:@"height"]);
}

أول كود هو تعريف فئة myPerson، حيث تحتوي الفئة على خاصية _height ولكن لا تقدم أي طرق الوصول getter/setter. وفي فئة testViewController هناك إشارة إلى جسم myPerson.

       عندما يتم إنشاء مثيل لـ myPerson، عادةً لا يمكن الوصول إلى خاصية _height لهذا الجسم، ولكن من خلال KVC تمكننا من القيام بذلك، والكود هو دالة testKVC.

       عندما يتم طباعة القيمة بعد التنفيذ، سيكون كما يلي:

2015-3-13 11:16:21.970 test[408:c07] testPerson’s init height = 0

2015-3-13 11:16:21.971 test[408:c07] testPerson’s height = 168

    هذا يعني أن هناك بالفعل قراءة و كتابة الخاصية _height.

    الطرق الشائعة لـ KVC:

- (id)valueForKey:(NSString *)key; -(void)setValue:(id)value forKey:(NSString *)key;

يقرأ طريقة valueForKey قيمة الخاصية بناءً على قيمة key، بينما يتم كتابة الخاصية بناءً على قيمة key باستخدام setValue:forKey:.

ملاحظة:

(1) يجب أن تكون قيمة key صحيحة، وإذا كانت هناك أخطاء في النطق، فإنه سيحدث استثناء.

(2) عند عدم تعريف قيمة key، يتم استدعاء الطريقة valueForUndefinedKey:، إذا كتبت هذه الطريقة نفسها، فإن قيمة key ستُدعى هنا عند حدوث خطأ في القيمة.

(3) لأن هناك تكرارًا لـkey في التشابك، لذا هناك مفهوم path المفتاحي، وهو ما يتم من خلال استخدامه نقاط السطر . لنقوم بربط كل key معًا، وبالتالي يمكن الوصول إلى هذا المسار.

(4) جميع NSArray/NSSet تدعم KVC

2、KVO هو اختصار لـKeyValue Observe، ويُعرف بالصينية بـمراقبة القيم المفتاحية. إنه نموذج مراقب شائع، حيث يتم إعلام المراقب عند تغيير القيم. يحتوي iOS على ميكانيكية إشعارات يمكن أن تحصل أيضًا على الإشعارات، ولكن هذا الميكانيكية يتطلب وجود مركز، بالمقارنة مع KVO فهي أكثر بساطة ووضوحًا.

      استخدام KVO بسيط جدًا، وهو بسيط في 3 خطوات.

      1. تسجيل العنصر الذي تحتاج إلى مراقبة خاصيته addObserver:forKeyPath:options:context:
      2. تنفيذ方法是 observeValueForKeyPath:ofObject:change:context:، هذا方法是 الذي يتم استدعاؤه تلقائيًا عند تغيير الخاصية المراقبة
      3. إزالة التسجيل كمراقب removeObserver:forKeyPath:context:

Demo:

@interface myPerson : NSObject 
{ 
  NSString *_name; 
  int   _age; 
  int   _height; 
  int   _weight; 
} 
@end 
@interface testViewController : UIViewController 
@property (nonatomic, retain) myPerson *testPerson; 
- (IBAction)onBtnTest:(id)sender; 
@end 
- (void)testKVO 
{ 
  testPerson = [[myPerson alloc] init]; 
  [testPerson addObserver:self forKeyPath:@"height" options:NSKeyValueObservingOptionNew context:nil]; 
} 
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
  if ([keyPath isEqualToString:@"height"]) { 
    NSLog(@"طول قد تغير! الجديد=%@", [change valueForKey:NSKeyValueChangeNewKey]); 
  } else { 
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
  } 
} 
- (IBAction)onBtnTest:(id)sender {}} 
  int h = [[testPerson valueForKey:@"height"] intValue];   
  [testPerson setValue:[NSNumber numberWithInt:h+1] forKey:@"height"]; 
  NSLog(@"person height=%@", [testPerson valueForKey:@"height"]); 
} 
- (void)dealloc 
{ 
  [testPerson removeObserver:self forKeyPath:@"height" context:nil]; 
  [super dealloc]; 
} 

第一段代码声明了myPerson类,里面有个_height的属性。在testViewController有一个testPerson的对象指针。

      在testKVO这个方法里面,我们注册了testPerson这个对象height属性的观察,这样当testPerson的height属性变化时, 会得到通知。在这个方法中还通过NSKeyValueObservingOptionNew这个参数要求把新值在dictionary中传递过来。

      重写了observeValueForKeyPath:ofObject:change:context:方法,这个方法里的change这个NSDictionary对象包含了相应的值。

      需要强调的是KVO的回调要被调用,属性必须是通过KVC的方法来修改的,如果是调用类的其他方法来修改属性,这个观察者是不会得到通知的。

3、NSNotification的用法见http://blog.csdn.net/eduora_meimei/article/details/44198909

区别:

delegate 的 优势 :

     1. 非常严格的语法。所有将听到的事件必须是在delegate协议中有清晰的定义。

     2. 如果delegate中的一个方法没有实现那么就会出现编译警告/خطأ

     3. 协议必须在controller的作用域范围内定义

      4.يمكن تتبع مسار التحكم في التطبيق ويعرف بوضوح

     5.يمكن تعريف عدة بروتوكولات مختلفة في المدرب الواحد، ويكون لكل بروتوكول وكلاء مختلفين

     6.لا يتطلب وجود عناصر ثالثة للحفاظ/المراقبة على عملية التواصل

     7.يتم استقبال القيم التي تعود من طرق البروتوكول. مما يعني أن الوكيل يمكنه تقديم ملاحظات إلى المدرب

      محدوديات :

     1.يتم كتابة الكثير من الكود: 1.تعريف البروتوكول؛ 2.خصائص الوكيل في المدرب؛ 3.تنفيذ طرق الوكيل في الوكيل نفسه

     2.عند إلغاء التسجيل للوكلاء، يجب أن يتم تغيير الوكيل بحذر إلى nil. إذا فشل الإعداد، فإن استدعاء طريقة إلغاء التسجيل للعنصر سيؤدي إلى حادث ذاكرة

     3.في المدرب الواحد، قد يكون هناك عدة أجزاء معبرة، وهي تلتزم بنفس البروتوكول، ولكن من الصعب إبلاغ العدة أجزاء بنفس الحدث، ولكن من الممكن

مزايا الإشعارات :

       1.لا يتطلب كتابة الكثير من الكود، وهو بسيط للتنفيذ

       2.يمكن لمتعدد العناصر الرد على الإشعارات المصدرة، أي تنفيذ بسيط من 1 إلى العديد

       3.يمكن للمدرب نقل عنصر السياق (dictionary) الذي يحمل معلومات مخصصة حول إصدار الإشعار

       محدوديات :

       1.لا يتم فحص الإشعارات في وقت التجميع لمعرفة ما إذا كانت قابلة للملاحظة بشكل صحيح من قبل الملاحظين؛

       2.عند إلغاء التسجيل للعناصر المسجلة، يجب إلغاء التسجيل من مركز الإشعارات؛

       3.يصبح من الصعب تتبع العمليات والتقنيات في الوقت الفعلي أثناء الت调试؛

       4.يتم استدعاء الطرف الثالث لإدارة الاتصال بين المدرب والملاحظين.

       5.يجب أن يعرف المدرب والملاحظون مسبقًا اسم الإشعار، وأحرف dictionary UserInfodictionary. إذا لم يتم تعريف هذه في منطقة العمل، فإن هناك احتمالًا لتزامن غير صحيح؛

       6.بعد إصدار الإشعار، لا يمكن للمدرب الحصول على أي ملاحظات من الملاحظين.

مزايا KVO :

        1.يتم تقديم طريقة بسيطة لتحقيق التوازي بين العناصر الثنائية. على سبيل المثال: التوازي بين model و view؛

        2.يتم الرد على تغييرات الحالة للعناصر غير المكتوبة، أي العناصر الداخلية، دون الحاجة إلى تعديل تنفيذ العناصر الداخلية (SKD objects);

        3.يتم تقديم القيم الجديدة والمسبقة للملاحظة للخصائص؛

        4.يتم ملاحظة الخصائص باستخدام paths الأساسية، لذا يمكن أيضًا ملاحظة الأجسام المدمجة؛

        5.تم إكمال التجريد من الملاحظة على العنصر الملاحظ، لأنه ليس من الضروري كتابة أي كود إضافي لسماح بملاحظة القيم الملاحظة

       محدوديات :

        1.المعلمات التي نلاحظها يجب أن يتم تعريفها باستخدام strings. لذلك لن يظهر أي تحذير أو فحص في معالج البرمجة؛

        2. إعادة هيكلة الخاصية ستجعل كود مراقبة الخاصية غير صالح.

        3. الحاجة إلى تعقيد جملة IF تتطلب أن يكون هناك تعقب للعديد من القيم من قبل الكائن.

        4. عند إطلاق الملاحظة لا تحتاج إلى إزالة الملاحظة.

1. بالتأكيد، كفاءة ديليجيت أعلى من notation.

يكون ديليجيت أكثر مباشرة من notation، وأحد الأنماط الأكثر وضوحًا هو أن ديليجيت غالبًا ما يحتاج إلى الانتباه إلى القيمة الإرجاعية، أي نتيجة ديليجيت. على سبيل المثال، -windowShouldClose:، يجب الانتباه إلى ما إذا كان الإرجاع yes أم no. لذلك غالبًا ما يحتوي ديليجيت على كلمة should، أي كما لو أنك تشغل ديليجيت لي، سأسألك إذا كنت ترغب في إغلاق النافذة، وستعطيني إجابة، وأقرر بناءً على إجابتك كيفية التصرف في الخطوة التالية. بينما تتميز notation بأنها لا تهتم بموقف المستلم، أنا فقط أصدح الإشعار، وها أنا ذا لا أهتم بأخذ موقف المستلم، ولا أهتم بالنتيجة. لذلك غالبًا ما تستخدم notation كلمة did، مثل NSWindowDidResizeNotification، حيث يصدح NSWindow عن هذا notification ولا يهتم بما بعد ذلك ولا ينتظر رد المستلم.

2. فرق كفو وnotation:

مثل ديليجيت، وظيفة كفو وnotation هي أيضًا اتصال بين فئتين من الفئات، ولكنها تختلف عن ديليجيت في أن 1) كلاهما مسؤول عن إصدار الإشعارات، ولا يهتم بالأمور الأخرى، لذلك لا يوجد قيمة إرجاع؛ 2) ديليجيت هو علاقة一对一، بينما هذان يمكن أن يكونا علاقة متعددة. أيضًا لهما خصائص خاصة.

شكرًا على القراءة، آمل أن تساعدكم، شكرًا لدعمكم لهذا الموقع!

مفضل لك