أجاب أندرو على سؤالك الرئيسي بأنه ، نعم ، سيتم استنزاف حمام السباحة التلقائي في كل دورة من حلقة التشغيل الرئيسية. لذلك أي كائنات autorelease تم إنشاؤها في viewDidLoad
قد يتم استنزافها على الفور عندما تعود إلى حلقة التشغيل الرئيسية. من المؤكد أنها لن يتم الاحتفاظ بها "حتى إنهاء التطبيق".
لكن يجب أن نكون حذرين: فأنت تفترض بوضوح أنه تتم إضافة هذه الكائنات إلى تجمع Autorelease. بعض التحذيرات لهذا الافتراض:
في الماضي (وما زال مطلوبًا لتواصل التشغيل ARC-MRC) ، عند إرجاع الكائنات من الطرق التي لم تبدأ أسماؤها alloc
, new
, copy
, ، أو mutableCopy
, ، ستؤدي هذه الكائنات إلى الحصول على الكائنات التلقائية ، والتي يتم تعاملها فقط عند استنزاف تجمع Autorelease (أي عندما عادت إلى حلقة التشغيل).
لكن Arc أصبح أكثر ذكاءً حول التقليل من الحاجة إلى برك Autorelease (انظر http://rentzsch.tumblr.com/post/75082194868/arcs-fast-autorelease, الذي يناقش callerAcceptsFastAutorelease
, ، ينادى الآن callerAcceptsOptimizedReturn
استدعى من قبل prepareOptimizedReturn
) ، لذلك غالبًا ما لن ترى هذا autorelease
سلوك. لذلك ، إذا كان كل من المكتبة والمتصل يستخدمان ARC ، فقد لا يتم وضع الكائنات في تجمع Autorelease ، ولكن Arc ستصدرها بذكاء على الفور إذا لم تكن هناك حاجة إليها.
مع مشاريع ARC المعاصرة ، لا يلزم عمومًا تجمعات Autorelease. لكن بعض الحالات الخاصة ، لا يزال بإمكان المرء الاستفادة من استخدام برك Autorelease. سأوضح إحدى تلك الحالات أدناه.
النظر في الرمز التالي:
#import "ViewController.h"
#import <sys/kdebug_signpost.h>
typedef enum : NSUInteger {
InnerLoop = 1,
MainLoop = 2
} MySignPostCodes;
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"png"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
kdebug_signpost_start(MainLoop, 0, 0, 0, 1);
for (int j = 0; j < 500; i++) {
NSData *data = [NSData dataWithContentsOfURL:fileURL];
UIImage *image = [[UIImage alloc] initWithData:data];
NSLog(@"%p", NSStringFromCGSize(image.size)); // so it's not optimized out
[NSThread sleepForTimeInterval:0.01];
}
kdebug_signpost_end(MainLoop, 0, 0, 0, 1);
});
}
@end
سيضيف الرمز التالي 500000 كائن إلى تجمع Autorelease ، والذي سيتم تجفيفه فقط عندما أعود إلى حلقة التشغيل:
في هذه الحالة ، يمكنك استخدام تجمع Autorelease لتقليل علامة المياه العالية:
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"png"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
kdebug_signpost_start(MainLoop, 0, 0, 0, 1);
for (int j = 0; j < 5; j++) {
@autoreleasepool {
kdebug_signpost_start(InnerLoop, 0, 0, 0, 2);
for (long i = 0; i < 100; i++) {
NSData *data = [NSData dataWithContentsOfURL:fileURL];
UIImage *image = [[UIImage alloc] initWithData:data];
NSLog(@"%p", NSStringFromCGSize(image.size)); // so it's not optimized out
[NSThread sleepForTimeInterval:0.01];
}
kdebug_signpost_end(InnerLoop, 0, 0, 0, 2);
}
}
kdebug_signpost_end(MainLoop, 0, 0, 0, 1);
});
}
@end
خلاصة القول ، مع ARC ، ليس من الواضح دائمًا عندما يستخدم كائنًا تلقائيًا وعندما يطلقه بشكل صريح عندما يسقط المتغير خارج النطاق. يمكنك دائمًا تأكيد ذلك من خلال فحص السلوك في الأدوات.
جانبا ، سأكون حذرا من رسم الكثير من استنتاجات إدارة الذاكرة العامة عند استخدام NSString
الفصل ، لأنه تم تحسينه بشكل كبير ولا يتوافق دائمًا مع ممارسات إدارة الذاكرة القياسية.