باستخدام المتغيرات سبيل المثال مع وقت التشغيل الحديثة

StackOverflow https://stackoverflow.com/questions/1007607

سؤال

لدي عدة سنوات من الخبرة في Obj-c و الكاكاو, ولكن أنا فقط الآن العودة إلى السلف من Obj-C 2.0 وما إلى ذلك.

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

ومع ذلك ، في الحرف الأول* و dealloc(على افتراض أنك لا تستخدم GC) أساليب يجب أن يكون استخدام ايفار مباشرة (في وقت الحالي).

حتى الأسئلة هي:

  1. يجب أن نستخدم accessors الخاصية في الحرف الأول* و dealloc مع الحديث التشغيل?

  2. إذا كان الأمر كذلك, لماذا هذا الاختلاف ؟ هو فقط لأن المترجم لا يستطيع رؤية ايفار?

  3. إذا كنت بحاجة إلى تجاوز أحد accessor لا يمكنني الوصول إلى هذا ايفار التي سوف يتم تحديدها في وقت التشغيل أو لا بد من تحديد الفعلي ايفار أن وقت التشغيل ثم استخدامها ؟

  4. مرة أخرى ، إذا لم يمكن الوصول إلى تصنيعه ايفار, لماذا لا أستطيع الاستمرار في فعل هذا من أجل التهيئة* و dealloc الأساليب ؟

قرأت مستندات عدة مرات ، ولكن يبدو أنها غامضة بعض الشيء عن كل هذا و أريد أن أكون متأكدا من أنني أفهم جيدا من أجل أن تقرر كيف تريد الاستمرار في الترميز.

أتمنى أن أسئلتي واضحة.


ملخص سريع من يختبر:

  1. إذا كنت لا تعلن ايفار في التراث, مترجم بالكامل التعيس

  2. إذا كنت تستخدم #ifndef __OBJC2__ حول ايفار في التراث مترجم سعيد و يمكنك استخدام كل ايفار مباشرة و الممتلكات

  3. في الحديث وقت التشغيل ، يمكنك ترك ايفار غير محدود الإقامة

  4. في وقت التشغيل الحديثة ، في محاولة الوصول ايفار مباشرة دون الإعلان يعطي خطأ أثناء ترجمة

  5. @private إعلان ايفار بالطبع يسمح الوصول المباشر إلى ايفار في والقديمة على حد سواء الحديثة

لا تعطي حقا وسيلة نظيفة على المضي قدما الآن أليس كذلك ؟

هل كانت مفيدة؟

المحلول

في التيار (OS X 10.5/دول مجلس التعاون الخليجي 4.0.1) مترجم ، لا يمكنك الوصول مباشرة إلى وقت تصنيعه ivars.جريج باركر أحد OS X runtime المهندسين وضعه هذا على الكاكاو-dev قائمة (مارس 12, 2009):

لا يمكنك الحالي مترجم.A في المستقبل يجب أن المترجم إصلاح ذلك.استخدام صراحة @خاص ivars في هذه الأثناء.An @خاص ايفار لا ينبغي أن تعتبر جزءا من العقد - هذا ما @خاص يعني القسري من قبل مترجم تحذيرات رابط أخطاء.

و لماذا ليس هناك طريقة تعلن صراحة المتغيرات سبيل المثال في .م ملف جديد التشغيل?

ثلاثة أسباب:(1) هناك بعض غير تافهة تفاصيل التصميم للعمل ، (2) مترجم-مهندس-ساعات محدودة, و (3) @خاص ivars هي عموما جيدة بما فيه الكفاية.

حتى الآن يجب استخدام نقطة-تدوين الوصول إلى خصائص ، حتى في init و dealloc.وهذا يتعارض مع أفضل الممارسات باستخدام ivars مباشرة في هذه الحالات, ولكن ليس هناك طريقة للتغلب على ذلك.أجد أن سهولة استخدام وقت التشغيل تصنيعه ivars (و مزايا الأداء) تفوق هذا في معظم الحالات.حيث كنت بحاجة إلى الوصول إلى ايفار مباشرة ، يمكنك استخدام @خاص ايفار جريج باركر يوحي (لا يوجد شيء يمنعك من الاختلاط أعلن صراحة و وقت تصنيعه ivars).

التحديث مع OS X 10.6, 64 بت التشغيل لا تسمح إمكانية الوصول المباشر إلى تصنيعه ivars عبر self->ivar.

نصائح أخرى

نظرًا لأن متغيرات الحالة نفسها لا يمكن تركيبها إلا في وقت التشغيل الحديث (ويجب الإعلان عنها في @interface تحت 32 بت أو ما قبل Leopard)، فمن الأكثر أمانًا/الأكثر قابلية للحمل أيضًا الإعلان عن ivar

  • هل يجب علينا استخدام أدوات الوصول إلى الخاصية في init* وdeloc مع Modern Runtime؟

قاعدتي الأساسية هي "ربما" ل -init*, و"عادة لا" ل -dealloc.

عند تهيئة كائن، تريد التأكد من نسخ/الاحتفاظ بقيم ivars بشكل صحيح.ما لم يكن لدى واضع الخاصية بعض الآثار الجانبية التي تجعله غير مناسب للتهيئة، فمن المؤكد إعادة استخدام التجريد الذي توفره الخاصية.

عند إلغاء تخصيص كائن، فأنت تريد تحرير أي كائنات ivar، ولكن لا تريد تخزين كائنات جديدة.إحدى الطرق السهلة للقيام بذلك هي ضبط الخاصية على الصفر (myObject.myIvar = nil)، والذي يستدعي في الأساس [myObject setMyIvar:nil].نظرًا لأنه يتم تجاهل الرسائل الموجهة إلى nil، فلا يوجد خطر في ذلك.ومع ذلك، فمن المبالغة عندما [إصدار myIvar]؛عادة ما يكون كل ما تحتاجه.بشكل عام، لا تستخدم الخاصية (أو أداة الضبط مباشرةً) في المواقف التي يجب أن يتصرف فيها إلغاء التخصيص بشكل مختلف عن تعيين المتغير.

أستطيع أن أفهم حجة eJames ضد استخدام أدوات الوصول إلى الخاصية في init/dealloc على الإطلاق، ولكن الجانب الآخر هو أنه إذا قمت بتغيير سلوك الخاصية (على سبيل المثال، التغيير من الاحتفاظ إلى النسخ، أو مجرد التعيين دون الاحتفاظ) ولا تستخدمها في init، أو العكس، يمكن أن يخرج السلوك عن المزامنة أيضًا.إذا كان يجب أن تعمل عملية تهيئة ivar وتعديله بنفس الطريقة، فاستخدم ملحق الخاصية لكليهما.

  • إذا كان الأمر كذلك، لماذا هذا مختلف؟هل هذا فقط لأن المترجم لا يمكنه رؤية ivar؟

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

  • إذا كنت بحاجة إلى تجاوز ملحق، فهل لا يزال بإمكاني الوصول إلى iVar الذي سيتم تعريفه في وقت التشغيل أو هل يجب علي تحديد iVar الفعلي الذي سيستخدمه وقت التشغيل بعد ذلك؟

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

  • مرة أخرى، إذا كان بإمكاني الوصول إلى iVar المركب، فلماذا لا أستطيع الاستمرار في القيام بذلك لطريقتي init* وdealloc؟

يجب أن تكون قادرًا على الوصول إلى الخاصية و/أو ivar في أي وقت بعد تخصيص المثيل.

هنالك سؤال SO آخر بمعلومات مماثلة، ولكنها ليست مكررة تمامًا.

خلاصة القول، من وثائق الهدف-C 2.0, ، ونقلا عن إجابة مارك بيسي على النحو التالي:

توجد اختلافات في السلوك تعتمد على وقت التشغيل (راجع أيضًا "اختلافات وقت التشغيل"):

بالنسبة لأوقات التشغيل القديمة، يجب أن يتم بالفعل الإعلان عن متغيرات المثيل في كتلة @interface.في حالة وجود متغير مثيل له نفس الاسم والنوع المتوافق مثل الخاصية، فسيتم استخدامه، وإلا فستحصل على خطأ في المحول البرمجي.

بالنسبة لأوقات التشغيل الحديثة، يتم تجميع متغيرات الحالة حسب الحاجة.إذا كان هناك متغير مثيل بنفس الاسم موجود بالفعل، فسيتم استخدامه.

فهمي هو كما يلي:

يجب ألا تستخدم أدوات الوصول إلى الخاصية في init* و dealloc للأسباب نفسها التي تمنعك من استخدامها في وقت التشغيل القديم:إنه يتركك عرضة للأخطاء المحتملة إذا قمت بتجاوز طرق الخاصية لاحقًا، وانتهى بك الأمر إلى القيام بشيء لا ينبغي القيام به init* أو dealloc.

يجب أن تكون قادرًا على تجميع ivar و تجاوز أساليب الملكية على النحو التالي:

@interface SomeClass
{
}
@property (assign) int someProperty;
@end

@implementation SomeClass
@synthesize someProperty; // this will synthesize the ivar
- (int)someProperty { NSLog(@"getter"); return someProperty; }
- (void)setSomeProperty:(int)newValue
{
    NSLog(@"setter");
    someProperty = newValue;
}
@end

مما يقودني إلى الاعتقاد بأنك ستكون قادرًا على الوصول إلى ivar المركب في ملفك init* و dealloc الأساليب كذلك.الشيء الوحيد الذي يمكنني التفكير فيه هو أن @synthesize قد يجب أن يأتي الخط قبل تعريفات الخاص بك init* و dealloc الطرق في الملف المصدر

في النهاية، بما أن الإعلان عن ivars في الواجهة لا يزال يعمل، فلا يزال هذا هو الرهان الأكثر أمانًا.

أنا أواجه نفس المشكلة.الطريقة التي أتعامل بها مع عدم القدرة على الوصول إلى متغيرات المثيلات المركبة هي كما يلي:

رأس عام

@interface MyObject:NSObject {
}
@property (retain) id instanceVar;
@property (retain) id customizedVar;
@end

رأس خاص / التنفيذ

@interface MyObject()
@property (retain) id storedCustomizedVar;
@end

@implementation MyObject
@synthesize instanceVar, storedCustomizedVar;
@dynamic customizedVar;

- customizedVar {
  if(!self.storedCustomizedVar) {
    id newCustomizedVar;
    //... do something
    self.storedCustomizedVar= newCustomizedVar;
  }
  return self.storedCustomizedVar;
}

- (void) setCustomizedVar:aVar {
  self.storedCustomizedVar=aVar;
}

@end

إنه ليس بهذه الأناقة، لكنه على الأقل يحافظ على نظافة ملف الرأس العام الخاص بي.

إذا كنت تستخدم KVO فأنت بحاجة إلى تحديد CustomVar كمفتاح تابع لـstoreCustomizedVar.

أنا جديد نسبيًا على Obj-C (ولكن ليس على البرمجة) ولقد كنت في حيرة من أمري بسبب هذا الموضوع.

الجانب الذي يقلقني هو أنه يبدو أنه من السهل نسبيًا استخدام iVar عن غير قصد بدلاً من الخاصية.على سبيل المثال الكتابة:

myProp = someObject;

بدلاً من

self.myProp = someObject;

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

من الناحية المثالية أفضّل أن أكون قادرًا على الحصول على وقت التشغيل لتطبيق بعض الأنماط على اسم الخاصية عند الإنشاء أي iVar.على سبيل المثالابدأ دائمًا بالبادئة "_".

من الناحية العملية، أقوم بذلك يدويًا في الوقت الحالي - معلنًا صراحةً عن الإيفار الخاص بي، وأعطيهم أسماء مختلفة عن الخصائص عن عمد.أستخدم البادئة "m" ذات النمط القديم، لذا إذا كانت الخاصية الخاصة بي هي "myProp"، فسيكون iVar الخاص بي هو "mMyProp".ثم أستخدم @synthesize myProp = mMyProp لربط الاثنين.

أعترف أن هذا أمر أخرق بعض الشيء، وقليل من الكتابة الإضافية، ولكن يبدو أن الأمر يستحق بالنسبة لي أن أكون قادرًا على إزالة الغموض بشكل أكثر وضوحًا في الكود.بالطبع لا يزال بإمكاني أن أخطئ وأكتب mMyProp = someObject، لكنني آمل أن تنبهني البادئة "m" إلى خطأي.

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

بالطبع هناك أيضًا الكثير من الأشياء الأخرى التي يمكنني فعلها بشكل خاطئ أيضًا ...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top