objective c - لماذا تستخدم ivar؟




objective-c ios (5)

عادة ما أرى هذا السؤال يسأل الآخر ، مثل يجب أن يكون كل ivar ممتلكات؟ (وأنا أحب الإجابة bbum لهذا Q).

أستخدم الخصائص تقريبًا بشكل حصري في شفرتي. لكن في كثير من الأحيان ، أعمل مع مقاول يتطور على نظام iOS لفترة طويلة ، وهو مبرمج تقليدي للعبة. يكتب مدونة تكشف عن أي خصائص تقريبا وتميل على ivars. أفترض أنه يفعل ذلك لأن 1.) اعتاد على ذلك لأن الخصائص لم تكن موجودة دائما حتى Objective C 2.0 (Oct '07) و 2.) للحصول على الحد الأدنى من كسب الأداء من خلال عدم الذهاب إلى getter / setter.

في حين أنه يكتب الكود الذي لا يتسرب ، فما زلت أفضِّل عليه استخدام الخصائص على ivars. تحدثنا عن ذلك ، ويرى إلى حد ما أنه ليس هناك سبب لاستخدام العقارات لأننا لم نستخدم KVO وأنه من ذوي الخبرة في الاهتمام بقضايا الذاكرة.

سؤالي أكثر ... لماذا تريد أن تستخدم فترة ivar - من ذوي الخبرة أم لا. هل هناك حقا هذا الفرق الكبير في الأداء الذي يمكن تبريره باستخدام ivar؟

أيضا كنقطة للتوضيح ، أقوم بتجاوز المستوطنين والأصحاب حسب الحاجة واستخدم ivar الذي يرتبط مع تلك الخاصية داخل الضيق / واضعة. ومع ذلك ، فإنني أستخدم دائمًا صيغة self.myProperty .

تحرير 1

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

// readonly for outsiders
@property (nonatomic, copy, readonly) NSString * name;

ولديك في استمرارية الصف:

// readwrite within this file
@property (nonatomic, copy) NSString * name;

لجعله "خاص" تمامًا لا يعلن عنه إلا في استمرارية الصف.


التغليف

إذا كان ivar خاص ، فإن الأجزاء الأخرى من البرنامج لا تستطيع الحصول عليه بسهولة. مع خاصية معلن عنها ، يمكن للأشخاص الأذكياء الوصول إليها والتحور بسهولة تامة عبر الواصلين.

أداء

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

أنواع غير بديهية

مثال: إذا كان لديك نوع C ++ ، فإن الوصول المباشر هو الطريقة الأفضل في بعض الأحيان. قد لا يكون النوع قابلاً للنسخ ، أو قد لا يكون بسيطًا للنسخ.

خاصية تعدد

كثير من ivars الخاص بك هي codependent. يجب التأكد من تكامل البيانات في سياق مؤشرات الترابط. وبالتالي ، قد تفضل الوصول المباشر إلى العديد من الأعضاء في الأقسام الهامة. إذا قمت بالالتصاق مع accessors للحصول على بيانات codependent ، فيجب أن تكون أقفال الخاصة بك عادة reentrant ، وسوف ينتهي بك الأمر في كثير من الأحيان إجراء المزيد من عمليات الاستحواذ (أكثر بكثير في بعض الأحيان).

تصحيح البرنامج

بما أن الفئات الفرعية يمكن أن تتجاوز أي طريقة ، قد ترى في النهاية أن هناك اختلافًا دلاليًا بين الكتابة إلى الواجهة مقابل إدارة الولاية بشكل مناسب. يعد الوصول المباشر لصحة البرنامج أمرًا شائعًا بشكل خاص في الحالات التي تم إنشاؤها جزئيًا - في dealloc وفي dealloc ، فمن الأفضل استخدام الوصول المباشر. قد تجد هذا أيضًا شائعًا في عمليات تنفيذ أداة accessor ، mutableCopy ملائم ، copy ، و mutableCopy ، وعمليات تنفيذ الأرشفة / التسلسل.

كما أنها أكثر تكرارا حيث أن المرء ينتقل من كل شيء له عقلية تلاقي readwrite العامة إلى واحدة تخفي تفاصيل التنفيذ / البيانات بشكل جيد. في بعض الأحيان ، تحتاج إلى أن تخطو بشكل صحيح حول الآثار الجانبية التي قد يحدثها تجاوز الطبقة الفرعية من أجل القيام بالشيء الصحيح.

حجم ثنائي

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

يقلل من التعقيد

في بعض الحالات ، من غير الضروري تمامًا إضافة + اكتب + الحفاظ على كل تلك السقالات الإضافية لمتغير بسيط مثل bool الخاص المكتوب بطريقة واحدة وقراءته في آخر.

هذا ليس على الإطلاق ليقول باستخدام خصائص أو accessors سيئة - لكل منها فوائد وقيود هامة. مثل العديد من لغات OO ونهج التصميم ، يجب عليك أيضًا تفضيل accessors مع رؤية مناسبة في ObjC. سيكون هناك أوقات تحتاج إلى الانحراف. ولهذا السبب ، أعتقد أنه من الأفضل في كثير من الأحيان تقييد الوصول المباشر إلى التطبيق الذي يعلن عن ivar (على سبيل المثال ، @private ).

إعادة تحرير 1:

لقد حفظ معظمنا كيفية استدعاء موصل خفي ديناميكيًا (طالما أننا نعرف الاسم…). في الوقت نفسه ، معظمنا لم يحفظ كيفية الوصول إلى ivars بشكل صحيح غير المرئي (خارج KVC). يساعد استمرار الفصل الدراسي ، ولكنه يقدم نقاط الضعف.

هذا الحل البديل واضح:

if ([obj respondsToSelector:(@selector(setName:)])
  [(id)obj setName:@"Al Paca"];

حاول الآن مع ivar فقط ، وبدون KVC.


السبب الأكثر أهمية هو مفهوم OOP لإخفاء المعلومات : إذا قمت بكشف كل شيء عن طريق الخصائص وبالتالي جعل الأجسام الخارجية تنظر إلى الأجزاء الداخلية لكائن آخر ، فسوف تستفيد من تلك الداخلية وبالتالي تعقيد تغيير التنفيذ.

يمكن أن يكتسب كسب "الحد الأدنى من الأداء" بسرعة ثم تصبح مشكلة. أنا أعرف من التجربة أنا أعمل على تطبيق يأخذ بالفعل iDevices إلى حدودها ، وبالتالي فإننا بحاجة إلى تجنب مكالمات الأسلوب غير الضرورية (بالطبع فقط حيثما يكون ذلك ممكنًا إلى حد معقول). وللمساعدة في تحقيق هذا الهدف ، نتجنب أيضًا بناء الجملة حيث أنه يجعل من الصعب رؤية عدد مكالمات الأسلوب في النظرة الأولى: على سبيل المثال ، كم عدد استدعاءات الأسلوب التي يقوم بها مشغل self.image.size.width للتعبير؟ على النقيض من ذلك ، يمكنك أن تقول على الفور مع [[self image] size].width . [[self image] size].width .

أيضا ، مع تسمية ivar الصحيح ، KVO ممكن بدون خصائص (IIRC ، لست خبيراً في KVO).


خصائص تعرض المتغيرات الخاصة بك إلى فئات أخرى. إذا كنت تحتاج فقط إلى متغير متعلق بالفئة التي تقوم بإنشائها فقط ، فاستخدم متغير مثيل. إليك مثال صغير: فصول XML لتحليل RSS والدورة المشابهة من خلال مجموعة من طرق التفويض. من العملي أن يكون لديك مثيل من NSMutableString لتخزين نتيجة كل نسخة مختلفة من التحليل. لا يوجد سبب وراء حاجة الطبقة الخارجية إلى الوصول إلى هذه السلسلة أو التلاعب بها. لذا ، فأنت تعلن ذلك في العنوان أو بشكل خاص ، ويمكنك الوصول إليه خلال الفصل الدراسي. قد يكون إعداد خاصية خاصة به مفيدًا فقط للتأكد من عدم وجود مشكلات في الذاكرة ، وذلك باستخدام self.mutableString لاستدعاء الواصل / المستأجرين.


خصائص مقابل متغيرات الحالة هو مفاضلة ، في النهاية يأتي الاختيار لأسفل إلى التطبيق.

اﻟﺗﻐﻟﯾف / اﻟﻣﻌﻟوﻣﺎت اﻹﺧﻔﺎء ھو أﻣر ﺟﯾد (TM) ﻣن ﻣﻧظور ﺗﺻﻣﯾم ، وواﺟﮭﺎت ﺿﯾﻘﺔ ، وﺻﻟﺔ ﺿﺋﯾﻟﺔ ھﻲ ﻣﺎ ﯾﺟﻌل اﻟﺑراﻣﺞ ﻗﺎﺑﻟﺔ ﻟﻟﺻﯾﺎﻧﺔ وﻣﻔﮭوﻣﺔ. من الصعب جدا في Obj-C إخفاء أي شيء ، لكن متغيرات الحالة المعلنة في التنفيذ تأتي في أقرب وقت ممكن.

الأداء في حين أن "التحسين المبكر لأوانه" هو شيء سيء (TM) ، كتابة التعليمات البرمجية سيئة الأداء فقط لأنك يمكن أن تكون على الأقل سيئة. من الصعب الجدال في مقابل أن يكون أسلوب المكالمة أكثر تكلفة من الحمل أو المتجر ، وفي الشفرة الحاسوبية المكثفة ، ستضاف التكلفة قريباً.

في لغة ثابتة مع خصائص ، مثل C # ، يمكن غالباً تحسين المكالمات إلى المستفيدين / getters بعيداً عن طريق المحول البرمجي. ومع ذلك ، فإن Obj-C تتسم بالديناميكية وإزالة مثل هذه المكالمات أصعب بكثير.

التجريد كانت الحجة ضد متغيرات الحالة في Obj-C تقليديا هي إدارة الذاكرة. مع وجود متغيرات حالة MRC تتطلب نداءات للاحتفاظ / إطلاق / autorelease للانتشار في جميع أنحاء الكود ، فإن الخصائص (المركبة أو لا) تحافظ على كود MRC في مكان واحد - مبدأ التجريد الذي هو شيء جيد (TM). لكن مع استخدام GC أو ARC ، يتم حذف هذه الوسيطة ، لذلك لم يعد التجريد لإدارة الذاكرة حجة ضد متغيرات الحالة.


دلالات

  • ما يمكن أن تعبرهproperty عن أن ivars لا تستطيع: غير nonatomic copy .
  • ما يمكن أن @property عن أنه لا يمكن لـ @property :

أداء

القصة القصيرة: ivars أسرع ، ولكن لا يهم بالنسبة لمعظم الاستخدامات. لا تستخدم الخصائص غير nonatomic الأقفال ، ولكن ivar المباشر أسرع لأنه يتخطى استدعاء الواصلين. للحصول على التفاصيل ، اقرأ الرسالة email التالية من lists.apple.com.

Subject: Re: when do you use properties vs. ivars?
From: John McCall <[email protected]>
Date: Sun, 17 Mar 2013 15:10:46 -0700

تؤثر الخصائص على الأداء بعدة طرق:

  1. كما تمت مناقشته بالفعل ، فإن إرسال رسالة للقيام بالتحميل / التخزين يكون أبطأ من مجرد إجراء التحميل / التخزين في المتجر .

  2. إن إرسال رسالة للقيام بالتحميل / المخزن هو أيضًا رمز أكثر قليلاً يحتاج إلى الاحتفاظ به في ذاكرة التخزين المؤقت i-cache: حتى إذا أضافت أداة getter / setter صفر تعليمات إضافية بخلاف التحميل / المخزن فقط ، فقد يكون هناك نصف صلب - قم بتعديل التعليمات الإضافية في المتصل لإعداد الرسالة لإرسال ومعالجة النتيجة.

  3. يؤدي إرسال رسالة إلى فرض إدخال هذا المحدد في ذاكرة التخزين المؤقت للطريقة ، ويتم تخزين هذه الذاكرة بشكل عام في ذاكرة التخزين المؤقت. يؤدي ذلك إلى زيادة وقت الإطلاق ، وزيادة استخدام الذاكرة الثابتة لتطبيقك ، وجعل مفاتيح السياق أكثر إيلاما. نظرًا لأن ذاكرة التخزين المؤقت للطريقة محددة للفئة الديناميكية لكائن ما ، فإن هذه المشكلة تزيد من استخدامك لـ KVO.

  4. يقوم إرسال رسالة بفرض انسكاب جميع القيم في الوظيفة إلى المكدس (أو الاحتفاظ بها في سجلات الحفظ المعتدلة ، والتي تعني فقط إراقة في وقت مختلف).

  5. قد يكون لرسالة ما آثار جانبية اعتباطية ، وبالتالي

    • يجبر المترجم على إعادة تعيين جميع افتراضاته حول الذاكرة غير المحلية
    • لا يمكن رفعها أو غرقها أو إعادة ترتيبها أو تلاحمها أو إزالتها.

  6. في ARC ، يتم دائمًا الاحتفاظ بنتيجة إرسال الرسالة ، إما من قبل المستدعي أو المتصل ، حتى بالنسبة لـ +0 المرتجعات: حتى إذا لم تحتفظ الطريقة / الاستغناء عن نتائجها ، لا يعرف المتصل ذلك ولديه في محاولة لاتخاذ إجراء لمنع النتيجة من الحصول على autoreleased. لا يمكن التخلص من هذا الأمر نظرًا لأن عمليات إرسال الرسائل ليست قابلة للتحليل بشكل ثابت.

  7. في ARC ، لأن طريقة الضبط تأخذ عادة حجة لها في +0 ، لا توجد طريقة "لنقل" الاحتفاظ بهذا الكائن (الذي ، كما نوقش أعلاه ، ARC عادة) في ivar ، لذلك يجب أن تحصل على القيمة بشكل عام الاحتفاظ / صدر مرتين .

لا شيء من هذا يعني أنها سيئة دائما ، بالطبع - هناك الكثير من الأسباب الجيدة لاستخدام العقارات. فقط ضع في اعتبارك أنه ، مثل العديد من ميزات اللغة الأخرى ، ليست حرة.


يوحنا.







ivar