تسرب ذاكرة iPhone غريب في محلل XML
-
06-07-2019 - |
سؤال
تحديث: لقد قمت بتحرير الكود ، لكن المشكلة لا تزال قائمة ...
مرحباً جميعاً،
هذا هو أول مشاركة لي هنا - لقد وجدت هذا المكان مجموعة رائعة لحل العديد من أسئلتي. عادةً ما أبذل قصارى جهدي لإصلاح أي شيء بمفردي ، لكن هذه المرة ليس لدي أي فكرة عن الخطأ ، لذلك آمل أن يساعدني شخص ما.
أقوم بإنشاء تطبيق iPhone يقوم بتوصيف اثنين من ملفات XML باستخدام TouchXML. لدي فئة XMLParser ، والتي تهتم بتنزيل النتائج وتحليلها. أحصل على تسرب الذاكرة عندما أقوم بتحليل ملف XML أكثر من مرة مع نفس مثيل XMLParser. فيما يلي أحد قصاصات التحليل (فقط الجزء ذي الصلة):
for(int counter = 0; counter < [item childCount]; counter++) {
CXMLNode *child = [item childAtIndex:counter];
if([[child name] isEqualToString:@"PRODUCT"])
{
NSMutableDictionary *product = [[NSMutableDictionary alloc] init];
for(int j = 0; j < [child childCount]; j++) {
CXMLNode *grandchild = [child childAtIndex:j];
if([[grandchild stringValue] length] > 1) {
NSString *trimmedString = [[grandchild stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[product setObject:trimmedString forKey:[grandchild name]];
}
}
// Add product to current category array
switch (categoryId) {
case 0:
[self.mobil addObject: product];
break;
case 1:
[self.allgemein addObject: product];
break;
case 2:
[self.besitzeIch addObject: product];
break;
case 3:
[self.willIch addObject: product];
break;
default:
break;
}
[product release];
}
}
في المرة الأولى ، أقوم بتحليل XML No Leak في الآلات ، في المرة القادمة التي أقوم فيها بذلك ، حصلت على الكثير من التسريبات (NSCFString / NSCFDictionary).
الآلات تشير لي إلى هذا الجزء داخل cxmlnode.m, ، عندما أحفر في كائن مسرب:
theStringValue = [NSString stringWithUTF8String:(const char *)theXMLString];
if ( _node->type != CXMLTextKind )
xmlFree(theXMLString);
}
return(theStringValue);
لقد أمضيت وقتًا طويلاً وحاولت طرقًا متعددة لإصلاح هذا ، ولكن دون جدوى حتى الآن ، ربما أفتقد شيئًا أساسيًا؟
أي مساعدة موضع تقدير كبير ، شكرا لك!
المحلول
من المحتمل أن تكون القضية في هذا السطر:
[self.mobil addObject:[product copy]];
عن طريق الدعوة إلى نسخة من product
أنت تقوم بإنشاء مثيل جديد nsmutabledictionary مع عدد الاحتفاظ بـ 1. mobil
مثال ، ومع ذلك ، سوف يزيد عدد النسخ عند إرساله addObject:
الرسالة ، وبالتالي فإن عدد النسخ هو الآن 2. بشكل عام ، يكون الكائن مسؤولاً عن التعامل مع ذاكرة الكائن الخاصة به ، لذلك في أي وقت تقوم بالرسالة setFoo:
أو addObject:
, ، يمكنك فقط تمرير الكائن مباشرة ، حتى لو تم تنشيطه أو تخطط لإصداره مباشرة بعد المكالمة ؛ تقع على عاتق المتلقي مسؤولية الاحتفاظ بالكائن الذي تمره إذا كان بحاجة إلى التمسك به.
نظرًا لأنك لم تقم بتعيين النسخة إلى أي متغير ، فلا يوجد لديك مؤشر يمكنك استخدامه لتقليل عدد النسخ التي تحتفظ بها الآن حيث لم تعد مهتمًا بها ، لذلك حتى لو mobil
تصدر نسخة المنتج في مرحلة ما ، لن تصل النسخة أبدًا إلى عدد الاحتفاظ بـ 0. [product release]
بيان في نهاية حلقة الصدفة الأصلية product
الكائن ، وليس النسخة التي أنشأتها.
بدلاً من ذلك ، جرب ما يلي ومعرفة ما إذا كانت الأدوات أكثر سعادة:
[self.mobil addObject:product];
نصائح أخرى
بعبارات بسيطة ، في كل مرة تستخدم فيها copy
, ، عليك أيضًا استخدامها release
/autorelease
مكان ما.
وفي هذه الحالة ، فإن الإجابة الأسهل هي عدم الاستخدام copy
في المقام الأول ، لأنك لا تفعل أي شيء مع الإصدار الأصلي من product
بعد نسخه.
لقد أصلحت المشكلة بنفسي. كان الأمر غبيًا ، لكن ربما قد يصادف شخص ما نفس الشيء ، لذلك سأقوم بنشره هنا.
1) لقد قمت بإعداد صفيف قابل للتغيير كمتغيرات مثيل مثل هذا:
@interface XMLParser : NSObject {
// ...
NSMutableArray *mobil;
// ...
}
@property(nonatomic, retain) NSMutableArray *mobil;
@end
في كل مرة أردت استعادة بيانات جديدة بداخلها:
self.mobil = nil ؛
الذي لم يفعل ما أردت القيام به ، لذلك هذا هو النهج الأفضل:
self.mobil removeallobjects] ؛
2) يجب أن تكون طريقة Dealloc مثل هذه لإصلاح التسريبات (لأن Mobil يتم تعريفه على أنه خاصية):
-(void) dealloc {
إطلاق موبيل] ؛
self.mobil = nil ؛
}
يا للعجب ، لقد كان هذا الكثير من العمل لمعرفة ذلك - آمل أن ينقذ شخصًا آخر بعض الوقت :-)