Diperlukan kumpulan autorelease untuk mengembalikan objek yang baru dibuat dari suatu metode. Misalnya pertimbangkan potongan kode ini:
- (NSString *)messageOfTheDay {
return [[NSString alloc] initWithFormat:@"Hello %@!", self.username];
}
String yang dibuat dalam metode akan memiliki jumlah tetap satu. Sekarang siapa yang akan menyeimbangkan jumlah tetap itu dengan rilis?
Metodenya sendiri? Tidak mungkin, harus mengembalikan objek yang dibuat, jadi tidak boleh melepaskannya sebelum kembali.
Penelepon metode ini? Penelepon tidak berharap untuk mengambil objek yang perlu dirilis, nama metode tidak menyiratkan bahwa objek baru dibuat, ia hanya mengatakan bahwa suatu objek dikembalikan dan objek yang dikembalikan ini mungkin yang baru yang membutuhkan rilis tetapi mungkin sebagai baik menjadi yang sudah ada yang tidak. Apa metode yang dikembalikan mungkin bahkan tergantung pada beberapa keadaan internal, sehingga penelepon tidak bisa tahu apakah harus melepaskan objek itu dan tidak harus peduli.
Jika penelepon harus selalu melepaskan semua objek yang dikembalikan oleh konvensi, maka setiap objek yang tidak baru dibuat harus selalu disimpan sebelum mengembalikannya dari suatu metode dan itu harus dilepaskan oleh penelepon setelah keluar dari ruang lingkup, kecuali dikembalikan lagi. Ini akan menjadi sangat tidak efisien dalam banyak kasus karena seseorang dapat sepenuhnya menghindari mengubah mempertahankan jumlah dalam banyak kasus jika penelepon tidak akan selalu melepaskan objek yang dikembalikan.
Itu sebabnya ada kolam autorelease, jadi metode pertama sebenarnya akan menjadi
- (NSString *)messageOfTheDay {
NSString * res = [[NSString alloc] initWithFormat:@"Hello %@!", self.username];
return [res autorelease];
}
Memanggil autorelease
objek menambahkannya ke kolam autorelease, tetapi apa artinya itu, menambahkan objek ke kolam autorelease? Ya, itu berarti memberi tahu sistem Anda, " Saya ingin Anda melepaskan objek itu untuk saya tetapi beberapa waktu kemudian, tidak sekarang; ia memiliki jumlah penahanan yang perlu diseimbangkan dengan rilis, jika tidak memori akan bocor tetapi saya tidak bisa melakukannya sendiri sekarang, karena saya perlu objek untuk tetap hidup di luar jangkauan saya saat ini dan penelepon saya tidak akan melakukannya untuk saya juga, itu tidak memiliki pengetahuan bahwa ini perlu dilakukan. Jadi tambahkan ke kolam Anda dan setelah Anda membersihkan itu kolam renang, juga membersihkan objek saya untuk saya. "
Dengan ARC, kompiler memutuskan kapan Anda akan menyimpan objek, kapan melepaskan objek, dan kapan menambahkannya ke kumpulan autorelease tetapi masih membutuhkan kehadiran kumpulan autorelease untuk dapat mengembalikan objek yang baru dibuat dari metode tanpa kebocoran memori. Apple baru saja membuat beberapa optimasi bagus untuk kode yang dihasilkan yang kadang-kadang akan menghilangkan kolam autorelease selama runtime. Optimalisasi ini mensyaratkan bahwa keduanya, penelepon dan callee menggunakan ARC (ingat mencampur ARC dan non-ARC adalah legal dan juga didukung secara resmi) dan jika itu sebenarnya kasusnya hanya dapat diketahui saat runtime.
Pertimbangkan Kode ARC ini:
// Callee
- (SomeObject *)getSomeObject {
return [[SomeObject alloc] init];
}
// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
Kode yang dihasilkan oleh sistem, dapat berperilaku seperti kode berikut (yaitu versi aman yang memungkinkan Anda untuk secara bebas mencampur kode ARC dan non-ARC):
// Callee
- (SomeObject *)getSomeObject {
return [[[SomeObject alloc] init] autorelease];
}
// Caller
SomeObject * obj = [[self getSomeObject] retain];
[obj doStuff];
[obj release];
(Perhatikan bahwa retain / release dalam pemanggil hanya mempertahankan keamanan defensif, itu tidak sepenuhnya diperlukan, kode akan benar tanpa itu)
Atau bisa berperilaku seperti kode ini, jika keduanya terdeteksi menggunakan ARC saat runtime:
// Callee
- (SomeObject *)getSomeObject {
return [[SomeObject alloc] init];
}
// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
[obj release];
Seperti yang Anda lihat, Apple menghilangkan atuorelease, dengan demikian juga pelepasan objek tertunda ketika kolam hancur, serta keselamatan tetap. Untuk mempelajari lebih lanjut tentang bagaimana itu mungkin dan apa yang sebenarnya terjadi di balik layar, lihat posting blog ini.
Sekarang untuk pertanyaan aktual: Mengapa orang menggunakannya @autoreleasepool
?
Bagi sebagian besar pengembang, hanya ada satu alasan yang tersisa hari ini untuk menggunakan konstruksi ini dalam kode mereka dan itu adalah untuk menjaga jejak memori kecil di mana berlaku. Misalnya pertimbangkan loop ini:
for (int i = 0; i < 1000000; i++) {
// ... code ...
TempObject * to = [TempObject tempObjectForData:...];
// ... do something with to ...
}
Asumsikan bahwa setiap panggilan tempObjectForData
dapat membuat yang baruTempObject
yang dikembalikan autorelease. For-loop akan membuat satu juta objek temp ini yang semuanya dikumpulkan dalam autoreleasepool saat ini dan hanya sekali kolam itu dihancurkan, semua objek temp dihancurkan juga. Sampai itu terjadi, Anda memiliki satu juta objek temp ini dalam memori.
Jika Anda menulis kode seperti ini sebagai gantinya:
for (int i = 0; i < 1000000; i++) @autoreleasepool {
// ... code ...
TempObject * to = [TempObject tempObjectForData:...];
// ... do something with to ...
}
Kemudian kumpulan baru dibuat setiap kali for-loop berjalan dan dihancurkan pada akhir setiap iterasi loop. Dengan cara itu paling banyak satu objek temp sedang nongkrong di memori setiap saat meskipun loop berjalan satu juta kali.
Di masa lalu, Anda sering harus mengelola sendiri autoreleasepools saat mengelola utas (misalnya menggunakan NSThread
) karena hanya utas utama yang secara otomatis memiliki kumpulan autorelease untuk aplikasi Cocoa / UIKit. Namun ini cukup banyak warisan hari ini karena hari ini Anda mungkin tidak akan menggunakan utas untuk memulai. Anda akan menggunakan GCD DispatchQueue
atau atau NSOperationQueue
keduanya dan keduanya mengelola kumpulan autorelease tingkat atas untuk Anda, dibuat sebelum menjalankan blok / tugas dan dihancurkan setelah selesai dengan itu.