سؤال

كما أفهمها، أي شيء تم إنشاؤه باستخدام تخصيص, جديد, ، أو ينسخ يجب أن يتم إصداره يدويًا.على سبيل المثال:

int main(void) {
    NSString *string;
    string = [[NSString alloc] init];
    /* use the string */
    [string release];
}

ولكن سؤالي هو: أليس هذا صحيحًا؟:

int main(void) {
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
    [pool drain];
}
هل كانت مفيدة؟

المحلول

نعم، مقتطف الرمز الثاني صالح تمامًا.

في كل مرة يتم إرسال -autorelease إلى كائن، تتم إضافته إلى تجمع التحرير التلقائي الداخلي.عندما يتم تصريف المجمع، فإنه ببساطة يرسل -release إلى كافة الكائنات الموجودة في المجمع.

تعد مجموعات الإصدار التلقائي مجرد وسيلة راحة تسمح لك بتأجيل إرسال الإصدار حتى "لاحقًا".يمكن أن يحدث ذلك "لاحقًا" في عدة أماكن، ولكن الأكثر شيوعًا في تطبيقات Cocoa GUI هو في نهاية دورة حلقة التشغيل الحالية.

نصائح أخرى

NSAutoreleasePool:استنزاف مقابليطلق

منذ وظيفة drain و release يبدو أنه يسبب ارتباكًا، فقد يكون من المفيد التوضيح هنا (على الرغم من أن هذا مشمول في وثائق...).

بالمعنى الدقيق للكلمة، من منظور الصورة الكبيرة drain يكون لا أي ما يعادل release:

في بيئة محسوبة بالمرجع، drain يقوم بنفس العمليات مثل release, ، لذا فإن الاثنين متساويان بهذا المعنى.للتأكيد، هذا يعني أنك تفعل لا تسرب بركة إذا كنت تستخدم drain بدلا من release.

في بيئة جمع القمامة، release هو عدم المرجع.وبالتالي ليس له أي تأثير. drain, من ناحية أخرى، يحتوي على تلميح للمجمع بأنه يجب عليه "الجمع إذا لزم الأمر".وهكذا في بيئة جمع القمامة، وذلك باستخدام drain يساعد على جمع توازن النظام عمليات المسح.

كما أشرنا سابقًا، فإن مقتطف الرمز الثاني الخاص بك صحيح.

أود أن أقترح طريقة أكثر إيجازًا لاستخدام مجموعة الإصدار التلقائي التي تعمل على جميع البيئات (عد المرجع، GC، ARC) وتتجنب أيضًا ارتباك الاستنزاف/الإصدار:

int main(void) {
  @autoreleasepool {
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
  }
}

في المثال أعلاه يرجى ملاحظة @autoreleasepool حاجز.تم توثيق هذا هنا.

لا أنت مخطئ.تنص الوثائق بوضوح على أنه في حالة عدم وجود GC، فإن -drain يعادل -release، مما يعني أن NSAutoreleasePool سوف لا يتم تسريبها.

ما قرأته من أبل:"في نهاية كتلة الإصدار التلقائي، يتم إرسال رسالة تحرير إلى الكائنات التي تلقت رسالة تحرير تلقائي داخل الكتلة - يتلقى الكائن رسالة تحرير في كل مرة يتم إرسال رسالة تحرير تلقائي فيها داخل الكتلة."

https://developer.apple.com/library/mac/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html

يؤدي إرسال الإصدار التلقائي بدلاً من التحرير إلى كائن إلى تمديد عمر هذا الكائن على الأقل حتى يتم تصريف التجمع نفسه (قد يكون أطول إذا تم الاحتفاظ بالكائن لاحقًا).يمكن وضع كائن في نفس التجمع عدة مرات، وفي هذه الحالة يتلقى رسالة تحرير في كل مرة يتم وضعه في التجمع.

نعم و لا.سينتهي بك الأمر إلى تحرير ذاكرة السلسلة ولكن "تسريب" كائن NSAutoreleasePool إلى الذاكرة باستخدام التصريف بدلاً من التحرير إذا قمت بتشغيل هذا ضمن بيئة مجمعة (غير مُدارة بالذاكرة).هذا "التسرب" يجعل ببساطة مثيل NSAutoreleasePool "غير قابل للوصول" مثل أي كائن آخر بدون مؤشرات قوية ضمن GC، وسيتم تنظيف الكائن في المرة التالية التي يتم فيها تشغيل GC، والتي يمكن أن تكون مباشرة بعد الاستدعاء إلى -drain:

بالُوعَة

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

وإلا فهو مثل كيف -release يتصرف تحت غير GC، نعم.وكما ذكر آخرون، -release يعد أمرًا محظورًا بموجب GC، وبالتالي فإن الطريقة الوحيدة للتأكد من أن التجمع يعمل بشكل صحيح ضمن GC هو من خلال -drain, ، و -drain تحت غير GC يعمل تماما مثل -release ضمن نطاق غير GC، ويمكن القول أنه ينقل وظائفه بشكل أكثر وضوحًا أيضًا.

يجب أن أشير إلى أن عبارة "أي شيء يتم استدعاؤه باستخدام new أو alloc أو init" يجب ألا تتضمن "init" (ولكن يجب أن تتضمن "copy")، لأن "init" لا يخصص الذاكرة، بل يقوم فقط بإعداد الكائن (المنشئ) موضة).إذا تلقيت كائنًا مخصصًا وكانت وظيفتك تسمى init فقط على هذا النحو، فلن تحرره:

- (void)func:(NSObject*)allocd_but_not_init
{
    [allocd_but_not_init init];
}

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

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