لماذا لا يتم إلغاء تخصيص الكائن عند استخدام ARC + NSZombieEnabled

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

سؤال

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

1) يستدعي المستخدمون الإجراء في RootViewController الذي يسبب أ SecondaryViewController ليتم إنشاؤها وتقديمها عبر presentModalViewController:animated.

2) SecondaryViewController يحتوي على ActionsController هذا هو NSObject فئة فرعية.

3) ActionsController يلاحظ إشعارًا عبر NSNotificationCenter عند تهيئته ويتوقف عن المراقبة عند إلغاء تخصيصه.

4) يرفض المستخدم SecondaryViewController للعودة إلى RootViewController.

مع إيقاف تشغيل تمكين كائنات Zombie، يعمل ما ورد أعلاه بشكل جيد، ويتم إلغاء تخصيص كافة الكائنات.مع تفعيل كائنات الزومبي ActionsController لم يتم إلغاء تخصيصها بالرغم من ذلك SecondaryViewController يتم إلغاء تخصيصها.

تسبب هذا في حدوث مشكلات في تطبيقي b/c NSNotificationCenter يستمر في إرسال الإخطارات إلى ActionsController وتتسبب المعالجات الناتجة في تعطل التطبيق.

لقد قمت بإنشاء تطبيق بسيط يوضح ذلك في https://github.com/xjones/XJARCTestApp.انظر إلى سجل وحدة التحكم مع تشغيل/إيقاف تمكين كائنات Zombie للتحقق من ذلك.

أسئلة)

  1. هل هذا السلوك الصحيح لتمكين كائنات الزومبي؟
  2. كيف يجب علي تنفيذ هذا النوع من المنطق لحل المشكلة.أرغب في الاستمرار في استخدام Enable Zombie Objects.

التعديل رقم 1:بناءً على اقتراح كيفن، أرسلت هذا إلى Apple وopenradar على http://openradar.appspot.com/10537635.

التعديل رقم 2:توضيح على إجابة جيدة

أولاً، أنا مطور iOS ذو خبرة وأفهم تمامًا ARC وكائنات الزومبي وما إلى ذلك.إذا فاتني شيء ما، بالطبع، فأنا أقدر أي إضاءة.

ثانيًا، صحيح أن الحل البديل لهذا العطل المحدد هو الإزالة actionsController كمراقب متى secondaryViewController يتم إلغاء تخصيصها.لقد وجدت أيضًا أنه إذا قمت بتعيين صراحةً actionsController = nil متى secondaryViewController تم إلغاء تخصيصه وسيتم إلغاء تخصيصه.كلا الحلين ليسا حلاً رائعًا ب/ج، فهما يتطلبان منك استخدام ARC بشكل فعال ولكن التعليمات البرمجية كما لو كنت لا تستخدم ARC (على سبيل المثال،لا يوجد iVars بشكل صريح في Dealloc).لا يساعد الحل المحدد أيضًا في تحديد متى قد تكون هذه مشكلة في وحدات التحكم الأخرى حتى يعرف المطورون بشكل حاسم متى/كيفية حل هذه المشكلة.

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

من الممكن تمامًا عدم وجود إجابة جيدة لأن هذا قد يكون خطأً في XCode.

شكرا لكم جميعا!

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

المحلول 3

تبين أنه خطأ iOS.لقد اتصلت بي شركة Apple وأوضحت أنها أصلحت هذه المشكلة في نظام التشغيل iOS 6.

نصائح أخرى

اتضح أنني كتبت بعض الهراء الخطير

إذا عملت الزومبي كما كتبت في الأصل، فإن تشغيل الزومبي سيؤدي مباشرة إلى عدد لا يحصى من النتائج الإيجابية الخاطئة...

هناك بعض الأحداث المزعجة التي تحدث، على الأرجح _objc_rootRelease, ، لذلك أي تجاوز dealloc لا يزال يتعين استدعاؤها مع تمكين الزومبي.الشيء الوحيد الذي لن يحدث مع الزومبي هو الاستدعاء الفعلي لهم object_dispose - على الأقل ليس بشكل افتراضي.

الأمر المضحك هو أنه إذا قمت ببعض التسجيل، فسوف ترى في الواقع أنه حتى مع تمكين ARC، فإن تنفيذك لـ dealloc سوف يتصل بتنفيذ الطبقة المتفوقة الخاصة به.

كنت أفترض في الواقع عدم رؤية هذا على الإطلاق:منذ ARC يولد هذه غير تقليدي .cxx_destruct طرق التخلص من أي __strong إيفارز من الطبقة، كنت أتوقع أن أرى هذا استدعاء الطريقة dealloc – إذا تم تنفيذه.

على ما يبدو، الإعداد NSZombieEnabled ل YES الأسباب .cxx_destruct لكي لا يتم استدعاؤك على الإطلاق - على الأقل هذا ما حدث عندما قمت بتحرير مشروعك النموذجي:
يؤدي إيقاف تشغيل الزومبي إلى التتبع العكسي وكلا عملية الإلغاء، بينما لا يؤدي تشغيل الزومبي إلى أي أثر رجعي بل إلغاء الإلغاء واحد فقط.

إذا كنت مهتمًا، فسيتم تضمين التسجيل الإضافي في شوكة المشروع العينة - يعمل عن طريق التشغيل فقط:هناك نوعان من المخططات المشتركة لتشغيل/إيقاف الزومبي.


الإجابة الأصلية (غير المنطقية):

وهذا ليس خطأ، ولكن الميزة.

وليس له علاقة بـ ARC.

NSZombieEnabled يحوم في الأساس dealloc للتنفيذ الذي بدوره يقوم بتحريك نوع هذا الكائن إليه _NSZombie - فئة وهمية تنفجر بمجرد إرسال أي رسالة إليها.هذا سلوك متوقع، وقد تم توثيقه – إذا لم أكن مخطئًا تمامًا.

هذا هو الخطأ الذي اعترفت به شركة Apple في الأسئلة والأجوبة الفنية QA1758.

يمكنك الحل البديل على iOS 5 وOS X 10.7 من خلال تجميع هذا الرمز في تطبيقك:

#import <objc/runtime.h>

@implementation NSObject (ARCZombie)

+ (void) load
{
    const char *NSZombieEnabled = getenv("NSZombieEnabled");
    if (NSZombieEnabled && tolower(NSZombieEnabled[0]) == 'y')
    {
        Method dealloc = class_getInstanceMethod(self, @selector(dealloc));
        Method arczombie_dealloc = class_getInstanceMethod(self, @selector(arczombie_dealloc));
        method_exchangeImplementations(dealloc, arczombie_dealloc);
    }
}

- (void) arczombie_dealloc
{
    Class aliveClass = object_getClass(self);
    [self arczombie_dealloc];
    Class zombieClass = object_getClass(self);

    object_setClass(self, aliveClass);
    objc_destructInstance(self);
    object_setClass(self, zombieClass);
}

@end

ستجد المزيد من المعلومات حول هذا الحل البديل في منشور مدونتي تصحيح الأخطاء مع تمكين ARC وZombies.

للإجابة على السؤال الثاني، ستحتاج إلى إزالة المراقب من NSNotification - وهذا سيمنعه من استدعاء العرض.

عادة، يمكنك القيام بذلك في صفقة التخصيص ولكن مع مشكلة الزومبي هذه ربما لا يتم الاتصال بها.ربما يمكنك وضع هذا المنطق في viewDidUnload؟

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

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