Overficive-C البسيط-الإفراط في الإفراج عن * يجب أن * يجب أن يتحطم. لماذا ا؟
-
28-09-2019 - |
سؤال
إما أن تصحيح الأخطاء الخاص بي مكسور أو هناك شيء أساسي لا أفهمه.
لدي بعض التعليمات البرمجية الأساسية في برنامج سطر الأوامر الأساسي للغاية ينبغي يصطدم. ومع ذلك ، فإنه لا يتحطم.
int main (int argc, const char * argv[])
{
NSString *string = [[NSString alloc] initWithString:@"Hello"];
[string release];
NSLog(@"Length: %d", [string length]);
return 0;
}
يطبع عبارة السجل "الطول: 5" كما تتوقع لسلسلة صالحة. ومع ذلك ، يجب تعامل السلسلة بحلول تلك النقطة و exec_bad_access
يجب إلقاء الخطأ.
لقد جربت هذا الرمز مع مرفق الأخطاء ودون مرفق التصحيح - كلاهما يعطي نفس النتيجة. لقد قمت أيضًا بتمكين (وتعطيل) NSZombie
, ، الذي يبدو أنه ليس له أي تأثير (اعتقدت في البداية أن هذه هي المشكلة منذ ذلك الحين NSZombie
لا يتم تعامل الكائنات أبدًا - لكنها لا تزال لا تتعطل NSZombie
معاق).
لدي نقاط توقف في بلدي المحلي .gdbinit
ملف لكسر أشياء مثل -[NSException raise]
و objc_exception_throw
. لدي أيضًا نقاط توقف على العديد من الطرق NSZombie
من أجل التقاطهم.
fb -[NSException raise]
fb -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:]
fb -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
#define NSZombies
# this will give you help messages. Set to NO to turn them off.
set env MallocHelp=YES
# might also be set in launch arguments.
set env NSZombieEnabled=YES
set env NSDeallocateZombies=NO
set env MallocCheckHeapEach=100000
set env MallocCheckHeapStart=100000
set env MallocScribble=YES
set env MallocGuardEdges=YES
set env MallocCheckHeapAbort=1
set env CFZombie 5
fb -[_NSZombie init]
fb -[_NSZombie retainCount]
fb -[_NSZombie retain]
fb -[_NSZombie release]
fb -[_NSZombie autorelease]
fb -[_NSZombie methodSignatureForSelector:]
fb -[_NSZombie respondsToSelector:]
fb -[_NSZombie forwardInvocation:]
fb -[_NSZombie class]
fb -[_NSZombie dealloc]
fb szone_error
fb objc_exception_throw
مع مجموعة نقاط التوقف هذه وتمكين NSZombie ، يجب أن أحصل على شيء مثل [NSString length]: message sent to deallocated instance 0x100010d39
طبعت إلى وحدة التحكم ، لكنني لا أرى هذا. أرى ال NSLog
طباعة الطول على أنها 5.
أرى سلوكًا مشابهًا مع فصول أخرى مثل NSURL
و NSNumber
. لكن بعض الفصول تعطل كما هو متوقع ، مثل NSError
و NSObject
.
هل هذا له علاقة بمجموعات الفصل؟ ألا يتبعون نفس القواعد فيما يتعلق بإدارة الذاكرة؟
إذا لم تكن مجموعات الفصل مرتبطة بهذه المشكلة ، فإن الميزة الشائعة الوحيدة التي يمكن أن أراه هي أن الفصول التي لا تصطدم بهذه الطريقة كلها مجردة مع نظير الأساس الأساسي. وهل من الممكن أن تفعل شيئا بحيال ذلك؟
المحلول
retain
/release
هو عقد بين واجهة برمجة التطبيقات والمبرمج أنه عندما تتبع القاعدة ، فإنه لا يعطل. لا يضمن العقد أنه إذا لم تتبع القاعدة ، فإنه ينهار!
في هذه الحالة،
[[NSString alloc] initWithString:@"Hello"]
مجرد إرجاع نفس الكائن مثل @"Hello"
كتحسين. ثابت NSString
لا يتم تعامله أبدًا ؛ كتحسين ، retain
و release
(على ما أظن) تجاهل. لهذا السبب لا يعطل.
يمكنك التحقق من تخميني من خلال مقارنة قيمة مؤشر @"Hello"
و string
.
نصائح أخرى
هذا مثال ممتاز على سبب الاحتفاظ بالتعدادات هي أداة تصحيح غير مجدية. من الخطأ أن نفترض -Rectain و -easease دائمًا إضافة أو إزالة 1 من عدد الاحتفاظ وأن العد الاحتفاظ هو ما تعتقد أنه ينبغي أن يكون.
محاولة
NSString *string = [[NSString alloc] initWithFormat:@"Hello %d", argc];
يجب أن يمنحك هذا سلسلة من شأنها أن تتصرف أكثر مثل الطريقة التي تتوقعها لأنك لا تقوم بتهيئة سلسلة من ثابت وقت الترجمة. ومع ذلك ، يتم تحذيرها ، مع تمكين الزومبي ، ستحصل على السلوك الذي تتوقعه ولكن بدون الزومبي ، قد يعمل NSLog جيدًا. على الرغم من أن السلسلة قد تم تعويضها ، إلا أن البيانات الموجودة في الكائن لا تزال موجودة في الذاكرة تاركة "شبحًا" يستجيب بشكل صحيح لبعض الرسائل.