سؤال

أحد أصدقائي طلب مني عدم استخدام NSException في تطبيقات آي فون.السبب قدم "أداء عنق الزجاجة".ولكن أنا غير مقتنع به.

شخص ما يمكن أن تؤكد لي أننا يجب أن تمتنع عن استخدام NSException في اي فون التطبيق ؟ إذا كان لديك أفضل الممارسات لاستخدام NSException ، يرجى تقديم ذلك أيضا.

تحديث:

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

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

المحلول

بالمختصر:

لا تستخدم استثناءات للإشارة إلى أي شيء سوى الأخطاء غير القابلة للاسترداد

من المناسب فقط استخدام @try/ @catch للتعامل مع الأخطاء غير القابلة للاسترداد. ليس من المناسب أبدًا استخدام@thow/@try/@catch للقيام بتدفق تحكم مثل العمليات على iOS أو Mac OS X. حتى ذلك الحين ، فكر بعناية ما إذا كنت أفضل حالًا باستخدام استثناء للإشارة إلى خطأ غير قابل للاسترداد أو ببساطة تعطل ( استدعاء Abort ()) ؛ الحادث غالبا ما يترك وراءه المزيد من الأدلة.

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

سلوك أي استثناء يتم إلقاؤه من خلال رمز إطار النظام غير محدد.


هل يمكنك شرح "سلوك أي استثناء يتم إلقاؤه من خلال رمز إطار النظام غير محدد." بالتفصيل؟

بالتأكيد.

تستخدم أطر عمل النظام تصميمًا حيث يعتبر أي استثناء خطأًا قاتلًا وغير قابل للاسترداد ؛ خطأ مبرمج ، لجميع النوايا والأغراض. هناك عدد محدود للغاية من الاستثناءات (HEH) لهذه القاعدة.

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

النظر في مكدس المكالمة:

your-code-1()
    system-code()
        your-code-2()

IE رمز حيث يستدعي رمزك في رمز النظام الذي يتصل بالمزيد من الكود الخاص بك (نمط شائع للغاية ، على الرغم من أن مكدسات المكالمات أعمق بشكل كبير).

إذا your-code-2 يلقي استثناء ، أن الاستثناءات تمر system-code يعني أن السلوك غير محدد ؛ system-code قد تترك أو لا تترك طلبك في حالة غير محددة أو محتملة أو مصقولة للبيانات.

أو بقوة أكبر: لا يمكنك إلقاء استثناء في your-code-2 مع توقع أن يمكنك التقاطه والتعامل معه فيه your-code-1.

نصائح أخرى

لقد استعملت معالجة الاستثناء بالنسبة لي مكثفة إلى حد ما التطبيق الصوت مع أية مشاكل على الإطلاق.بعد الكثير من القراءة و قليلا من القياس والتفكيك والتحليل ، لقد جاء إلى إثارة للجدل استنتاج أنه لا يوجد سبب حقيقي عدم استخدامها (بذكاء) والكثير من سبب لعدم (NSError مؤشر المؤشرات التي لا نهاية لها الشرطية...يع!).معظم ما يقوله الناس على المنتديات هو مجرد تكرار أبل مستندات.

أذهب إلى القليل من التفاصيل في هذا بلوق وظيفة ولكن سوف مخطط بلدي النتائج هنا:

أسطورة 1:@حاول/@الصيد/@أخيرا مكلف جدا (من حيث وحدة المعالجة المركزية)

على اي فون بلدي 4, رمي واصطياد 1 مليون الاستثناءات يستغرق حوالي 8.5 ثانية.وهذا يعادل حوالي 8.5 ميكرو لكل منها.مكلفة في الوقت الحقيقي كويك تايم الموضوع ؟ ربما قليلا (ولكن كنت لا رمي الاستثناءات هناك أنت؟؟), ولكن 8.5 ميكرو ثانية تأخير في UIAlert إخبار المستخدم كان هناك مشكلة في فتح الملف سيكون لاحظت ؟

الأسطورة 2:@حاول كتل تكلفة على 32bit دائرة الرقابة الداخلية

أبل مستندات الكلام من "صفر التكلفة @حاول الكتل على 64bit"وعلى الدولة أن 32 بت تتحمل تكلفة.قليلا القياس والتفكيك والتحليل يبدو أنها تشير إلى أن هناك صفر التكلفة @حاول الكتل على 32bit دائرة الرقابة الداخلية (معالج ARM) كذلك.لم أبل أقصد أن أقول 32bit إنتل?

أسطورة 3:المهم أن استثناءات من خلال الكاكاو الأطر غير معروف

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

حافة واحدة هنا مع أساليب مثل NSObject:performSelectorOnMainThread:waitUntilDone:.إذا كان في وقت لاحق المعلمة نعم هذه الأفعال مثل متزامن وظيفة في هذه الحالة قد غفر لكم تتوقع الاستثناء فقاعة تصل إلى الاتصال الخاص بك نطاق.على سبيل المثال:

/////////////////////////////////////////////////////////////////////////
#pragma mark - l5CCThread
/////////////////////////////////////////////////////////////////////////

@interface l5CCThread : NSThread @end

@implementation l5CCThread

- (void)main
{
    @try {

        [self performSelectorOnMainThread:@selector(_throwsAnException) withObject:nil waitUntilDone:YES];

    } @catch (NSException *e) {
        NSLog(@"Exception caught!");
    }
}
- (void)_throwsAnException { @throw [NSException exceptionWithName:@"Exception" reason:@"" userInfo:nil]; }

@end

/////////////////////////////////////////////////////////////////////////
#pragma mark - l5CCAppDelegate
/////////////////////////////////////////////////////////////////////////

@implementation l5CCAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    l5CCThread *thd = [[l5CCThread alloc] init];
    [thd start];

    return YES;
}
// ...

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

لماذا استخدام NSException على NSError هو

أي شخص من أي وقت مضى العمل في واحدة من كبار السن ج-بناء أطر مثل الصوت الأساسية يعلم ما واجبا هو فحص ومعالجة أخطاء التقارير.الفائدة الرئيسية @حاول/@الصيد NSExceptions يوفر جعل الخاص بك رمز أنظف وأسهل للمحافظة عليه.

نقول لديك 5 خطوط من التعليمات البرمجية التي تعمل على الملف.كل قد رمي واحد من 3 أخطاء مختلفة (على سبيل المثال من مساحة القرص ، قراءة خطأ ، إلخ.).بدلا من التفاف كل سطر في المشروط الذي يتحقق لا قيمة الإرجاع ثم جهات خارجية NSError مؤشر التحقيق إلى آخر ObjC الأسلوب (أو أسوأ من ذلك ، يستخدم #define ماكرو!), يمكنك لف كل 5 خطوط في واحد @محاولة التعامل مع كل خطأ هناك.أعتقد خطوط عليك إنقاذ!

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

أمثلة من كل هذا و المزيد من التفاصيل حول المعايير والتفكيك هي في هذا بلوق وظيفة...

الاستثناءات بالإضافة إلى محاولة/الصيد/أخيرا هو النموذج المستخدمة من قبل كل رئيسية لغة (C++, Java, PHP, Ruby, Python).ربما حان الوقت لإسقاط جنون العظمة و تبني عليه وكذلك...على الأقل في دائرة الرقابة الداخلية.

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

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