سؤال

لقد كنت أستخدم الكتل منذ بعض الوقت، ولكني أشعر أن هناك أشياء أفتقدها فيما يتعلق بإدارة الذاكرة في كل من البيئات ARC والبيئات غير التابعة لـ ARC.أشعر أن الفهم الأعمق سيجعلني أتخلص من العديد من حالات تسرب الذاكرة.

AFNetworking هو استخدامي الرئيسي للكتل في تطبيق معين.في معظم الأحيان، داخل معالج إكمال العملية، أفعل شيئًا مثل "[self.myArray addObject]".

في كل من البيئات التي تدعم ARC والبيئات غير الممكّنة لـ ARC، سيتم الاحتفاظ بكلمة "ذاتي" وفقًا لـ هذه المقالة من أبل.

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

ومع ذلك، لم أعثر على تحذير إلا مؤخرًا ولم أتمكن من فهمه.أنا أستخدم ARC في هذا المثال بالذات.

لدي متغيرين للمثيل يشيران إلى اكتمال وفشل عملية الشبكة

@property (nonatomic, readwrite, copy) SFCompletionBlock completionBlock;
@property (nonatomic, readwrite, copy) SFFailureBlock failureBlock;
@synthesize failureBlock = _failureBlock;
@synthesize operation = _operation;

في مكان ما في الكود، أفعل هذا:

[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id
                                                    responseObject) {
NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
            _failureBlock(error);
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"nothing");
        }];

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

ومع ذلك، لدي الأسئلة/الملاحظات التالية.

1) إذا قمت بتغيير _failureBlock(error) إلى "self.failureBlock(error)" (بدون علامتي الاقتباس) يتوقف المترجم عن الشكوى.لماذا هذا؟هل هذا تسرب للذاكرة يفتقده المترجم؟

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

أرغب في سماع أفكار الآخرين حول ARC وغير ARC فيما يتعلق بالكتل والمشكلات/الحلول المتعلقة بإدارة الذاكرة.أجد هذه المواقف عرضة للخطأ وأشعر أن إجراء بعض المناقشات حول هذا الأمر ضروري لتوضيح الأمور.

لا أعرف إذا كان الأمر مهمًا، لكني أستخدم Xcode 4.4 مع أحدث إصدار من LLVM.

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

المحلول

1) إذا قمت بتغيير _failureBlock (خطأ) إلى "Self.FailureBlock (خطأ)" (بدون اقتباس) يتوقف المترجم الشكوى. لماذا هذا؟ هذا هو تسرب الذاكرة يفتقد التحويل البرمجي؟

دورة الاحتفاظ موجودة في كلتا الحالتين. إذا كنت تستهدف iOS 5+، فيمكنك نقل مرجع ضعيف إلى الذات:

giveacodicetagpre.

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

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

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

giveacodicetagpre.

نصائح أخرى

هذا يعني أنه كلما تم استدعاء كتلة إكمال من عملية شبكة AFNetworking ، يتم الاحتفاظ بالذات داخل تلك الكتلة ، ويتم إصدارها عندما تنفد هذه الكتلة.

لا، self يتم الاحتفاظ بها بواسطة الكتلة عند إنشاء الكتلة.ويتم تحريره عندما يتم إلغاء تخصيص الكتلة.

أعتقد أن Xcode على حق:تحتفظ كتلة الفشل بالذات ، وتحتفظ بنسختها الخاصة من الكتلة ، لذلك لن يتم تحديد أي من الاثنين.

الكتلة المعنية التي تحتفظ بها self هي كتلة الإكمال التي تم تمريرها إلى setCompletionBlockWithSuccess. self لا يحمل إشارة إلى هذه الكتلة.بدلاً من، self.operation (يفترض نوعا ما NSOperation) يحتفظ بالكتل أثناء تنفيذها.لذلك هناك دورة مؤقتا.ومع ذلك، عند الانتهاء من تنفيذ العملية، سيتم كسر الدورة.

1) إذا قمت بتغيير _FailureBlock (خطأ) إلى "Self.FailureBlock (خطأ)" (بدون عروض أسعار) توقف المترجم عن الشكوى.لماذا هذا؟هل هذا تسرب ذاكرة يخطئ المترجم؟

لا ينبغي أن يكون هناك فرق. self يتم القبض عليه في كلتا الحالتين.لا يُضمن للمترجم التقاط كافة حالات دورات الاحتفاظ.

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