Objective-C ARC: kuat vs mempertahankan dan lemah vs menetapkan

367

Ada dua atribut manajemen memori baru untuk properti yang diperkenalkan oleh ARC, strongdan weak.

Terlepas dari copy, yang jelas merupakan sesuatu yang sama sekali berbeda, apakah ada perbedaan antara strongvs retaindan weakvs assign?

Dari pemahaman saya, satu-satunya perbedaan di sini adalah yang weakakan menetapkan nilke pointer, sementara assigntidak akan, yang berarti program akan macet ketika saya mengirim pesan ke pointer setelah dirilis. Tetapi jika saya menggunakan weak, ini tidak akan pernah terjadi, karena mengirim pesan ke niltidak akan melakukan apa-apa.

Saya tidak tahu tentang perbedaan antara strongdan retain.

Apakah ada alasan mengapa saya harus menggunakan assigndan retaindalam proyek-proyek baru, atau jenis yang ditinggalkan?

Jakub Arnold
sumber
12
Ada tiga atribut manajemen memori baru untuk properti yang diperkenalkan oleh ARC strong, weakdan unsafe_unretained.
NJones
5
@NJones Ada dua atribut properti ( weakdan strong) dan 4 kualifikasi seumur hidup variabel ( __strong, __weak, __unsafe_unretained, __autoreleasing). Lihat Catatan ARC di bawah ini.
Snowcrash
1
@SnowCrash Ada versi Xcode, kemungkinan pratinjau pengembang, di mana menggunakan assignsaat kompilasi dengan ARC adalah kesalahan. Ada banyak jawaban yang dihapus tentang ini. Sepertinya itu sudah berubah sebelum rilis final. unsafe_unretainedadalah atribut yang disukai banyak dari kita pengguna awal. Sebagai bukti, unsafe_unretainedini adalah atribut yang terlihat di Apple "Programming With Objective-C" di bawah bagian "Encapsulating Data" di bawah subjudul "Gunakan Referensi Tidak Terjamin untuk Beberapa Kelas". Yang mengatakan: "Untuk properti, ini berarti menggunakan atribut unsafe_unretained:"
NJones

Jawaban:

230

Dari Transitioning to ARC Release Notes (contoh di bagian atribut properti).

// The following declaration is a synonym for: @property(retain) MyClass *myObject;

@property(strong) MyClass *myObject;

Begitu strongjuga dengan retaindalam deklarasi properti.

Untuk proyek-proyek ARC yang akan saya gunakan strongsebagai pengganti retain, saya akan gunakan assignuntuk properti primitif C dan weakuntuk referensi lemah ke objek Objective-C.

JeremyP
sumber
11
Bahkan, di bawah ARC itu adalah kesalahan kompilasi yang digunakan assignuntuk objek. Anda harus menggunakan salah satu weakatau unsafe_unretained(yang tidak aman, jelas) jika Anda tidak ingin mempertahankan properti.
cobbal
5
assignmengkompilasi dengan baik bagi saya dalam proyek ARC dengan target penyebaran 4.0.
Pascal
8
@Pascal: referensi lemah tidak diperbolehkan di target penyebaran di mana os tidak 5.0 atau lebih tinggi. Jadi untuk proyek yang lebih lama Anda masih dapat menggunakan assign, tetapi jika Anda pindah ke versi yang lebih baru Anda harus beralih ke yang lemah
Mattia
1
Tampak seperti Xcode 4 (dengan ARC) menghasilkan NSManagedObject subclass menggunakan retainvs strong. Saya kira itu sebagian besar tidak berbahaya, tetapi saya membayangkan itu harus stronguntuk konsistensi ... atau mungkin tidak masalah. stackoverflow.com/questions/7796476/…
Joe D'Andrea
3
@ JeremyP Ya, jawaban Anda tepat. Saya bereaksi terhadap @Mattia. Saya menunjukkan bahwa assignmasih berlaku dalam beberapa kasus.
Steven Oxley
606

Setelah membaca begitu banyak artikel, posting Stackoverflow, dan aplikasi demo untuk memeriksa atribut atribut variabel, saya memutuskan untuk menggabungkan semua informasi atribut:

  1. atom // default
  2. nonatomik
  3. strong = retain // default
  4. lemah
  5. menahan
  6. tetapkan // default
  7. tidak aman_tidak dijaga
  8. salinan
  9. dibaca saja
  10. readwrite // default

Di bawah ini adalah tautan artikel terperinci di mana Anda dapat menemukan semua atribut yang disebutkan di atas, yang pasti akan membantu Anda. Terima kasih banyak kepada semua orang yang memberikan jawaban terbaik di sini !!

Atribut properti variabel atau Pengubah di iOS

1.strong (iOS4 = retain)

  • dikatakan "simpan ini di tumpukan sampai saya tidak menunjuk lagi"
  • dengan kata lain "Saya pemiliknya, Anda tidak dapat membatalkan ini sebelum membidik dengan baik seperti mempertahankan"
  • Anda menggunakan kuat hanya jika Anda perlu mempertahankan objek.
  • Secara default semua variabel instan dan variabel lokal adalah pointer kuat.
  • Kami biasanya menggunakan yang kuat untuk UIViewControllers (orang tua item UI)
  • kuat digunakan dengan ARC dan itu pada dasarnya membantu Anda, dengan tidak perlu khawatir tentang mempertahankan jumlah objek. ARC secara otomatis melepaskannya untuk Anda ketika Anda selesai dengan itu. Menggunakan kata kunci yang kuat berarti bahwa Anda memiliki objek.

Contoh:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

2. lemah -

  • ia mengatakan "simpan ini selama orang lain menunjukkannya dengan kuat"
  • hal yang sama seperti assign, no retain atau release
  • Referensi "lemah" adalah referensi yang tidak Anda pertahankan.
  • Kami biasanya menggunakan yang lemah untuk IBOutlets (UIViewController's Childs). Ini berfungsi karena objek anak hanya perlu ada selama objek induknya.
  • referensi yang lemah adalah referensi yang tidak melindungi objek yang dirujuk dari pengumpulan oleh pengumpul sampah.
  • Lemah pada dasarnya menetapkan, properti yang tidak ditangguhkan. Kecuali ketika objek dideallocated, pointer lemah secara otomatis diatur ke nol

Contoh:

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@synthesize myButton;

Penjelasan Kuat & Lemah, Terima Kasih kepada BJ Homer :

Bayangkan objek kita adalah seekor anjing, dan anjing itu ingin melarikan diri (dideallocated).

Pointer yang kuat seperti tali pada anjing. Selama Anda memiliki tali pengikat pada anjing, anjing itu tidak akan lari. Jika lima orang mengikatkan tali penuntun mereka pada satu anjing, (lima penunjuk kuat pada satu benda), maka anjing itu tidak akan melarikan diri sampai kelima tali penuntun terlepas.

Pointer yang lemah, di sisi lain, seperti anak kecil yang menunjuk ke arah anjing dan berkata, "Lihat! Seekor anjing!" Selama anjing itu masih terikat, anak-anak kecil masih bisa melihat anjing itu, dan mereka masih akan menunjuk ke sana. Namun, segera setelah semua tali terlepas, anjing itu melarikan diri tidak peduli berapa banyak anak kecil yang menunjuk padanya.

Segera setelah penunjuk kuat terakhir (tali penuntun) tidak lagi menunjuk ke suatu objek, objek tersebut akan dibatalkan alokasinya, dan semua penunjuk lemah akan dihilangkan.

Kapan kita menggunakan yang lemah?

Satu-satunya waktu Anda ingin menggunakan lemah, adalah jika Anda ingin menghindari siklus mempertahankan (misalnya orang tua mempertahankan anak dan anak mempertahankan orang tua sehingga tidak pernah dilepaskan).

3. tetap = kuat

  • itu dipertahankan, nilai lama dilepaskan dan ditugaskan mempertahankan menetapkan nilai baru harus dikirim
  • mempertahankan penugasan dan nilai lama dikirim -rilis
  • mempertahankan sama dengan kuat.
  • apple mengatakan jika Anda tetap mempertahankannya maka otomatis akan dikonversi / berfungsi seperti kuat saja.
  • metode seperti "alokasi" termasuk "penyimpanan" implisit

Contoh:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4. ditugaskan

  • assign adalah default dan hanya melakukan assignment variabel
  • assign adalah atribut properti yang memberi tahu kompiler bagaimana mensintesis implementasi setter properti
  • Saya akan menggunakan assign untuk properti primitif C dan lemah untuk referensi lemah ke objek Objective-C.

Contoh:

@property (nonatomic, assign) NSString *address;

@synthesize address;
swiftBoy
sumber
5
2. "referensi yang lemah adalah referensi yang tidak melindungi objek yang dirujuk dari pengumpulan oleh pengumpul sampah" - tidak ada yang namanya objektif c sebagai pengumpul sampah;
bucherland
1
dan hierarki ini dikelola oleh iOS secara otomatis. Baca tentang konsep MVC. Maksud saya ketika ViewContorller sedang disajikan, iOS memuat hierarki tampilan di layar (membuat tampilan tidak ada). Ketika ViewController lain disajikan, hierarki tampilan pertama ini tidak dapat dialokasikan. Tetapi jika Anda memiliki 'kuat' di ViewController, maka tampilan ini tidak dapat di-deallocated, ketika layar mati. Yang bisa berdampak keras pada memori perangkat dan menyebabkan perlambatan aplikasi. (Tentu saja perangkat memiliki banyak memori dan Anda pasti akan baik-baik saja pada aplikasi layar 5-10, tetapi dalam aplikasi besar Anda akan mendapat masalah)
bucherland
1
Kapan kita menggunakan yang lemah? 1. Untuk objek UI, 2. delegasi, 3. blok (lemahSelf harus digunakan alih-alih diri untuk menghindari siklus memori (seperti yang disebutkan di atas)
bucherland
1
Ada satu kesalahan dalam jawaban yang bagus ini - kuat - "ARC secara otomatis melepaskannya untuk Anda ketika Anda selesai dengan itu", ini tidak benar. ARC akan secara otomatis melepaskan objek yang lemah ketika tidak ada pointer ke mereka. Strong - adalah sinonim untuk mempertahankan, jadi objek tetap dipertahankan dan merupakan tanggung jawab kita untuk membuat objek nihil
Ashwin G
1
@RDC, Apa defaultmaksudnya? Jika saya menggunakan @property (nonatomic) NSString *stringitu strong? Atau assign? Karena keduanya adalah default.
Iulian Onofrei
40

nonatomik / atom

  • nonatomik jauh lebih cepat daripada atom
  • selalu menggunakan nonatomik kecuali jika Anda memiliki persyaratan yang sangat spesifik untuk atom, yang seharusnya langka (atom tidak menjamin keamanan ulir - hanya warung yang mengakses properti saat secara bersamaan disetel oleh utas lain)

kuat / lemah / tetapkan

  • gunakan kuat untuk mempertahankan objek - meskipun kata kunci tetap identik, yang terbaik adalah menggunakan kuat
  • gunakan lemah jika Anda hanya ingin pointer ke objek tanpa mempertahankannya - berguna untuk menghindari siklus mempertahankan (mis. delegasi) - itu akan secara otomatis menghilangkan pointer ketika objek dilepaskan
  • gunakan assign untuk primitif - persis seperti lemah kecuali tidak nihil objek saat dirilis (ditetapkan secara default)

(Pilihan)

salinan

  • menggunakannya untuk membuat salinan objek yang dangkal
  • praktik yang baik untuk selalu menetapkan properti yang tidak dapat diubah untuk disalin - karena versi yang dapat berubah dapat dipindahkan ke properti yang tidak dapat diubah, salinan akan memastikan bahwa Anda akan selalu berurusan dengan objek yang tidak dapat diubah
  • jika objek yang tidak dapat diubah dilewatkan, ia akan mempertahankannya - jika objek yang dapat diubah dilewatkan, ia akan menyalinnya

dibaca saja

  • menggunakannya untuk menonaktifkan pengaturan properti (mencegah kode dari kompilasi jika ada pelanggaran)
  • Anda dapat mengubah apa yang disampaikan oleh pengambil dengan mengubah variabel secara langsung melalui variabel instan, atau dalam metode pengambil itu sendiri
Vadoff
sumber
@ Sakthimuthiah benar, Anda harus memperbaiki jawaban Anda.
Adela Toderici
@ Sakthimuthiah salah (dan siapa pun yang mengatakannya). Atomic TIDAK membuatnya aman, meskipun dapat dengan mudah keliru karena perilakunya. Silakan baca: stackoverflow.com/questions/12347236/…
Chris J
39

Sejauh yang saya tahu, strongdan retainsinonim, sehingga mereka melakukan hal yang persis sama.

Maka weakhampir seperti assign, tetapi secara otomatis diatur ke nil setelah objek, itu menunjuk ke, tidak dapat dialokasikan.

Itu artinya, Anda cukup menggantinya.

Namun , ada satu kasus khusus yang saya temui, di mana saya harus menggunakan assign, daripada weak. Katakanlah kita memiliki dua properti delegateAssigndan delegateWeak. Dalam keduanya disimpan delegasi kami, yaitu memiliki kami dengan memiliki satu-satunya referensi yang kuat. Delegasi tersebut melakukan deallocating, jadi -deallocmetode kita dipanggil juga.

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething];
    [delegateAssign doSomething];
}

Delegasi sudah dalam proses deallokasi, tetapi masih belum sepenuhnya dialokasikan. Masalahnya adalah bahwa weakreferensi kepadanya sudah dibatalkan! Properti delegateWeakberisi nil, tetapi delegateAssignberisi objek yang valid (dengan semua properti sudah dirilis dan dibatalkan, tetapi masih valid).

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething]; // Does nothing, already nil.
    [delegateAssign doSomething]; // Successful call.
}

Ini adalah kasus yang cukup khusus, tetapi ini menunjukkan kepada kita bagaimana weakvariabel - variabel itu bekerja dan kapan mereka dibatalkan.

Tricertops
sumber
20

Dokumen Clang tentang Objective-C Automatic Reference Counting (ARC) menjelaskan kualifikasi dan pengubah kepemilikan dengan jelas:

Ada empat kualifikasi kepemilikan:

  • __ autoreleasing
  • __ kuat
  • __ * tidak aman_tidak dilindungi *
  • __ lemah

Suatu tipe secara nontrivial memiliki kualifikasi kepemilikan jika memenuhi kualifikasi dengan __ autoreleasing , __ kuat , atau __ lemah .

Lalu ada enam pengubah kepemilikan untuk properti yang dinyatakan:

  • menetapkan menyiratkan __ * kepemilikan * tidak aman * tidak dimiliki.
  • salinan menyiratkan __ kepemilikan yang kuat , serta perilaku semantik salinan yang biasa pada penyetel.
  • mempertahankan menyiratkan __ kepemilikan yang kuat .
  • kuat menyiratkan __ kepemilikan yang kuat .
  • * unsafe_unretained * menyiratkan __ * unsafe_unretained * kepemilikan.
  • lemah menyiratkan lemahnya kepemilikan.

Dengan pengecualian lemah , pengubah ini tersedia dalam mode non-ARC.

Semantik bijaksana, kualifikasi kepemilikan memiliki arti yang berbeda dalam lima operasi yang dikelola : Membaca, Penugasan, Inisialisasi, Penghancuran dan Memindahkan, di mana sebagian besar waktu kita hanya peduli tentang perbedaan dalam operasi Penugasan.

Penugasan terjadi ketika mengevaluasi operator penugasan. Semantik bervariasi berdasarkan kualifikasi:

  • Untuk __ benda kuat , pointee baru dipertahankan pertama kali; kedua, nilainya dimuat dengan semantik primitif; ketiga, pointee baru disimpan ke dalam nilai dengan semantik primitif; dan akhirnya, pointee lama dilepaskan. Ini tidak dilakukan secara atom; sinkronisasi eksternal harus digunakan untuk membuat ini aman dalam menghadapi beban dan penyimpanan secara bersamaan.
  • Untuk __ benda lemah , nilai diperbarui ke titik ke titik yang baru, kecuali titik yang baru adalah objek yang saat ini sedang mengalami deallokasi, di mana nilai tersebut diperbarui ke pointer nol. Ini harus mengeksekusi secara atomis berkenaan dengan penugasan lain untuk objek, untuk membaca dari objek, dan untuk rilis akhir dari pointee baru.
  • Untuk objek __ * unsafe_unretained *, pointee baru disimpan ke dalam nilai menggunakan semantik primitif.
  • Untuk objek autoreleasing __ , pointee baru dipertahankan, autoreleased, dan disimpan ke dalam nilai menggunakan semantik primitif.

Perbedaan lain dalam Reading, Init, Destruction dan Moving, silakan merujuk ke Bagian 4.2 Semantik dalam dokumen .

Mingming
sumber
6

Untuk memahami referensi Strong dan Lemah, perhatikan contoh di bawah ini, misalkan kita memiliki metode yang dinamai displayLocalVariable.

 -(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
  }

Dalam lingkup metode di atas variabel myName terbatas pada metode displayLocalVariable, setelah metode selesai variabel myName yang memegang string "ABC" akan mendapatkan deallocated dari memori.

Sekarang bagaimana jika kita ingin memegang nilai variabel myName sepanjang siklus hidup pengontrol tampilan kita. Untuk ini, kita dapat membuat properti bernama nama pengguna yang akan memiliki referensi kuat ke variabel myName (lihat self.username = myName;di bawah kode), seperti di bawah ini,

@interface LoginViewController ()

@property(nonatomic,strong) NSString* username;
@property(nonatomic,weak) NSString* dummyName;

- (void)displayLocalVariable;

@end

@implementation LoginViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

}

-(void)viewWillAppear:(BOOL)animated
{
     [self displayLocalVariable];
}

- (void)displayLocalVariable
{
   NSString myName = @"ABC";
   NSLog(@"My name is = %@", myName);
   self.username = myName;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}


@end

Sekarang dalam kode di atas Anda dapat melihat myName telah ditetapkan untuk self.username dan self.username memiliki referensi yang kuat (seperti yang kita nyatakan dalam antarmuka menggunakan @property) ke myName (secara tidak langsung itu memiliki referensi kuat ke string "ABC"). Karenanya String myName tidak akan dapat dialokasikan dari memori sampai self.username hidup.

  • Referensi yang lemah

Sekarang pertimbangkan untuk menetapkan myName ke dummyName yang merupakan referensi Lemah, self.dummyName = myName; Tidak seperti referensi kuat. Lemah hanya akan memegang nama saya sampai ada referensi kuat untuk nama saya. Lihat kode di bawah ini untuk memahami referensi Lemah,

-(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
     self.dummyName = myName;
  }

Dalam kode di atas ada referensi lemah ke myName (yaitu self.dummyName memiliki referensi lemah ke myName) tetapi tidak ada referensi kuat untuk myName, maka self.dummyName tidak akan dapat memegang nilai myName.

Sekarang pertimbangkan lagi kode di bawah ini,

-(void)displayLocalVariable
      {
         NSString myName = @"ABC";
         NSLog(@"My name is = %@", myName);
         self.username = myName;
         self.dummyName = myName;
      } 

Dalam kode di atas self.username memiliki referensi Strong ke myName, maka self.dummyName sekarang akan memiliki nilai myName bahkan setelah metode berakhir karena myName memiliki referensi Strong yang terkait dengannya.

Sekarang setiap kali kita membuat referensi Strong ke suatu variabel, jumlah retainnya bertambah satu dan variabel tidak akan mendapatkan deallocated, retain count mencapai 0.

Semoga ini membantu.

Mahadev Mandale
sumber
2

Kuat:

  • Properti tidak akan Hancurkan tetapi Hanya sekali Anda mengatur properti ke nol akan objek akan hancur
  • Secara default semua variabel instan dan variabel lokal adalah pointer kuat.
  • Anda menggunakan kuat hanya jika Anda perlu mempertahankan objek.
  • Kami biasanya menggunakan yang kuat untuk UIViewControllers (orang tua item UI)
  • IOS 4 (non-ARC) Kita Dapat Menggunakan Retain KeyWord
  • IOS 5 (ARC) Kita Dapat Menggunakan Kata Kunci Yang Kuat

Contoh: @property (kuat, nonatomik) ViewController * viewController;

@ mensintesis viewController;

Lemah

Secara default, secara otomatis dapatkan dan atur ke nol

  • Kami biasanya menggunakan yang lemah untuk IBOutlets (Anak-anak UIViewController's) dan mendelegasikan
  • hal yang sama seperti assign, no retain atau release

Contoh: @ properti (lemah, non-atomik) IBOutlet UIButton * myButton;

@ mensintesis myButton;

Nikunj Patel
sumber
1

Perbedaan antara yang kuat dan yang dipertahankan:

  • Di iOS4, kuat sama dengan mempertahankan
  • Ini berarti bahwa Anda memiliki objek dan menyimpannya di tumpukan sampai tidak menunjukkannya lagi
  • Jika Anda menulis retain maka secara otomatis akan berfungsi seperti kuat

Perbedaan antara yang lemah dan yang ditetapkan:

  • Referensi "lemah" adalah referensi yang tidak Anda pertahankan dan Anda menyimpannya selama orang lain menunjukkannya dengan kuat
  • Ketika objek "deallocated", pointer lemah secara otomatis diatur ke nol
  • Atribut properti "assign" memberi tahu kompiler bagaimana mensintesis implementasi setter properti
Chen Rui
sumber