Apakah perlu menggunakan autoreleasepool dalam program Swift?

96

Pada halaman 17 dari presentasi WWDC14 ini , dikatakan

Bekerja dengan Objective-C? Masih harus mengelola autorelease pools
autoreleasepool {/ * code * /}

Apa artinya? Apakah ini berarti bahwa jika basis kode saya tidak memiliki file Objective-C, autoreleasepool {}apakah tidak diperlukan?

Dalam jawaban dari pertanyaan terkait , ada contoh yang autoreleasepoolbisa berguna:

- (void)useALoadOfNumbers {
    for (int j = 0; j < 10000; ++j) {
        @autoreleasepool {
            for (int i = 0; i < 10000; ++i) {
                NSNumber *number = [NSNumber numberWithInt:(i+j)];
                NSLog(@"number = %p", number);
            }
        }
    }
}

Jika kode di atas diterjemahkan ke Swift dengan autoreleasepooldrop, apakah Swift cukup pintar untuk mengetahui bahwa numbervariabel harus dilepaskan setelah yang pertama }(seperti beberapa bahasa lain)?

Ethan
sumber
1
Tampaknya tidak ada dokumentasi tentang autoreleasepoolSwift. Saya memperluas pertanyaan Anda dan menanyakannya di forum pengembang .
Aaron Brager

Jawaban:

198

The autoreleasepoolpola yang digunakan di Swift ketika kembali autoreleaseobjek (dibuat oleh salah kode Objective-C atau menggunakan kelas Cocoa). The autoreleasepola dalam fungsi Swift banyak seperti itu tidak di Objective-C. Misalnya, pertimbangkan rendisi Swift metode Anda (instantiating NSImage/ UIImageobjek):

func useManyImages() {
    let filename = pathForResourceInBundle

    for _ in 0 ..< 5 {
        autoreleasepool {
            for _ in 0 ..< 1000 {
                let image = NSImage(contentsOfFile: filename)
            }
        }
    }
}

Jika Anda menjalankan ini di Instrumen, Anda akan melihat grafik alokasi seperti berikut:

dengan autoreleasepool

Tetapi jika Anda melakukannya tanpa kumpulan rilis otomatis, Anda akan melihat bahwa penggunaan memori puncak lebih tinggi:

tanpa autoreleasepool

Itu autoreleasepool memungkinkan Anda untuk mengelola secara eksplisit saat objek autorelease dibatalkan alokasinya di Swift, seperti yang bisa Anda lakukan di Objective-C.

Catatan: Saat menangani objek asli Swift, biasanya Anda tidak akan menerima objek rilis otomatis. Inilah mengapa presentasi menyebutkan peringatan tentang hanya membutuhkan ini saat "bekerja dengan Objective-C", meskipun saya berharap Apple lebih jelas dalam hal ini. Tapi jika Anda berurusan dengan objek Objective-C (termasuk kelas Cocoa), mereka mungkin objek autorelease, dalam hal ini rendisi Swift @autoreleasepoolpola Objective-C ini masih berguna.

rampok
sumber
2
Pada semua pertanyaan ini, Anda dapat menulis kelas Anda sendiri, dan membuatnya printlnmasuk deinit, dan ini menjadi sangat mudah untuk memverifikasi secara tepat ketika objek dibatalkan alokasinya. Atau amati di Instrumen. Sebagai jawaban atas pertanyaan Anda, tampaknya objek Swift dikembalikan dari fungsi dengan jumlah retensi +1 (bukan objek autorelease), dan pemanggil akan mengelola kepemilikan dengan mulus dari titik itu (misalnya, jika dan saat objek yang dikembalikan berada di luar cakupan, segera dialokasikan, tidak ditempatkan di alat autoreleasepool).
Rob
3
@StevenHernandez Kumpulan peluncuran otomatis tidak ada hubungannya dengan kebocoran. Kebocoran disebabkan oleh benda yang belum dirilis. Pool Autorelease, di sisi lain, hanyalah kumpulan objek yang rilisnya ditangguhkan hingga pool tersebut dikuras. Pool tidak mengontrol apakah sesuatu dibatalkan alokasinya atau tidak, melainkan hanya waktu deallokasi tersebut. Lihat kembali tampilan peta, Anda tidak dapat mengontrol apa yang dilakukan caching (menggunakan memori, tetapi bukan kebocoran yang sebenarnya) atau melakukan apa pun jika ada kebocoran nyata (dan saya tidak mengetahui adanya kebocoran tampilan peta yang signifikan, meskipun secara historis telah ada kebocoran acak dan sederhana di UIKit).
Rob
2
@matt Ya, saya melihat perilaku serupa. Jadi saya mengulangi latihan saya dengan NSImage/ UIImageobjek dan mewujudkan masalah secara lebih konsisten (dan, terus terang, ini adalah contoh masalah yang lebih umum, karena penggunaan memori puncak seringkali hanya bermasalah saat menangani objek yang lebih besar; contoh praktis dari ini mungkin rutinitas mengubah ukuran banyak gambar). Saya juga mereproduksi perilaku yang memanggil kode Objective-C yang secara eksplisit membuat objek autorelease. Jangan salah paham: Saya pikir kita membutuhkan kumpulan rilis otomatis di Swift lebih jarang daripada di Objective-C, tetapi masih memiliki peran untuk dimainkan.
Rob
1
Saya menemukan contoh yang berhasil! Panggil saja NSBundle pathForResource:ofType:berulang kali.
matt
1
pathForResource:ofType:Contoh saya tidak lagi berfungsi di Xcode 6.3 / Swift 1.2. :)
matt
5

Jika Anda akan menggunakannya dalam kode Objective-C yang setara, maka Anda akan menggunakannya di Swift.

akankah Swift cukup pintar untuk mengetahui bahwa variabel angka harus dilepaskan setelah yang pertama}

Hanya jika Objective-C melakukannya. Keduanya beroperasi di sepanjang aturan manajemen memori Cocoa.

Tentu saja ARC tahu bahwa numberkeluar dari ruang lingkup pada akhir iterasi loop tersebut, dan jika dipertahankan, itu akan melepaskannya di sana. Namun, itu tidak memberi tahu Anda apakah objek itu dirilis secara otomatis, karena -[NSNumber numberWithInt:] mungkin atau mungkin tidak mengembalikan instance yang dirilis secara otomatis. Tidak mungkin Anda dapat mengetahuinya, karena Anda tidak memiliki akses ke sumber-[NSNumber numberWithInt:] .

newacct
sumber
1
Jika Swift berperilaku sama dengan Objective-C untuk ini, mengapa presentasi menyebutkan "Bekerja dengan Objective-C?" secara khusus?
Ethan
9
@Ethan Tampaknya objek Swift asli bukan objek autorelease, dan autoreleasepoolkonstruksinya sama sekali tidak diperlukan. Tetapi jika kode Swift Anda menangani objek Objective-C (termasuk objek Cocoa), objek tersebut mengikuti pola autorelease, dan dengan demikian autoreleasepoolkonstruksi menjadi berguna.
Rob
Saya mengerti bahwa "Autoreleasepool memungkinkan Anda untuk mengelola secara eksplisit saat objek autorelease dibatalkan alokasinya di Swift" tetapi mengapa saya ingin melakukannya? Mengapa / tidak bisa kompiler melakukannya untuk saya? Saya harus menambahkan autoreleasepool saya sendiri untuk mencegah VM melewati atap dalam lingkaran ketat manipulasi string besar. Jelas bagi saya di mana itu harus ditambahkan, dan itu bekerja dengan sempurna. Mengapa kompiler tidak bisa melakukannya? Bisakah kompilator dibuat lebih pintar untuk melakukan pekerjaan dengan baik?
vonlost