سؤال

تحديث: لقد قمت بتحرير الكود ، لكن المشكلة لا تزال قائمة ...

مرحباً جميعاً،
هذا هو أول مشاركة لي هنا - لقد وجدت هذا المكان مجموعة رائعة لحل العديد من أسئلتي. عادةً ما أبذل قصارى جهدي لإصلاح أي شيء بمفردي ، لكن هذه المرة ليس لدي أي فكرة عن الخطأ ، لذلك آمل أن يساعدني شخص ما.
أقوم بإنشاء تطبيق 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 ؛
}

يا للعجب ، لقد كان هذا الكثير من العمل لمعرفة ذلك - آمل أن ينقذ شخصًا آخر بعض الوقت :-)

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