Katakanlah saya memiliki kelas yang dipanggil SomeClass
dengan string
nama properti:
@interface SomeClass : NSObject
{
NSString* name;
}
@property (nonatomic, retain) NSString* name;
@end
Saya mengerti bahwa nama dapat diberikan NSMutableString
dalam hal ini dapat menyebabkan perilaku yang salah.
- Untuk string secara umum, apakah selalu lebih baik menggunakan
copy
atribut bukanretain
? - Apakah properti "yang disalin" dengan cara apa pun kurang efisien daripada properti "yang dipertahankan-ed" seperti itu?
objective-c
cocoa
cocoa-touch
PlagueHammer
sumber
sumber
name
dirilisdealloc
atau tidak?Jawaban:
Untuk atribut yang tipenya adalah kelas nilai tidak berubah yang sesuai dengan
NSCopying
protokol, Anda hampir selalu harus menentukancopy
dalam@property
deklarasi Anda . Menentukanretain
adalah sesuatu yang hampir tidak pernah Anda inginkan dalam situasi seperti itu.Inilah mengapa Anda ingin melakukan itu:
Nilai
Person.name
properti saat ini akan berbeda tergantung pada apakah properti itu dinyatakanretain
ataucopy
- itu akan menjadi@"Debajit"
jika properti ditandairetain
, tetapi@"Chris"
jika properti ditandaicopy
.Karena di hampir semua kasus Anda ingin mencegah mutasi atribut objek di belakangnya, Anda harus menandai properti yang mewakili mereka
copy
. (Dan jika Anda menulis sendiri penyetel alih-alih menggunakan,@synthesize
Anda harus ingat untuk benar-benar menggunakannyacopy
daripadaretain
di dalamnya.)sumber
NSMutableString
, kecuali sebagai tipe "string builder" sementara (dari mana saya langsung mengambil salinan abadi). Saya lebih suka mereka menjadi tipe yang bijaksana - tetapi saya akan membiarkan fakta bahwa salinan bebas untuk melakukan retain jika string asli tidak bisa berubah mengurangi sebagian besar kekhawatiran saya.Salinan harus digunakan untuk NSString. Jika itu Mutable, maka itu akan disalin. Jika tidak, maka hanya akan dipertahankan. Tepatnya semantik yang Anda inginkan dalam suatu aplikasi (biarkan tipe melakukan yang terbaik).
sumber
NSString
properti yang dinyatakancopy
akan mendapatkanretain
pula (jika itu tidak berubah, tentu saja). Contoh lain yang bisa saya pikirkan adalahNSNumber
.Ya - secara umum selalu menggunakan atribut salin.
Ini karena properti NSString Anda dapat melewati instance NSString atau instance NSMutableString , dan oleh karena itu kami tidak dapat benar-benar menentukan apakah nilai yang diteruskan adalah objek yang tidak dapat diubah atau dapat diubah.
Jika properti Anda diberikan instance NSString , jawabannya adalah " Tidak " - penyalinan tidak kurang efisien daripada mempertahankan.
(Ini tidak kalah efisien karena NSString cukup pintar untuk tidak benar-benar melakukan salinan.)
Jika properti Anda lulus instance NSMutableString maka jawabannya adalah " Ya " - menyalin kurang efisien daripada mempertahankan.
(Ini kurang efisien karena alokasi memori dan penyalinan yang sebenarnya harus terjadi, tetapi ini mungkin hal yang diinginkan.)
Secara umum, properti "yang disalin" memiliki potensi untuk menjadi kurang efisien - namun melalui penggunaan
NSCopying
protokol, dimungkinkan untuk mengimplementasikan kelas yang "sama efisien" untuk disalin dan dipertahankan. Contoh NSString adalah contoh dari ini.Anda harus selalu menggunakan
copy
ketika Anda tidak ingin keadaan internal properti berubah tanpa peringatan. Bahkan untuk objek yang tidak dapat diubah - objek yang tidak dapat diubah yang ditulis dengan benar akan menangani penyalinan secara efisien (lihat bagian selanjutnya tentang kekekalan danNSCopying
).Mungkin ada alasan kinerja untuk
retain
objek, tetapi itu datang dengan overhead pemeliharaan - Anda harus mengelola kemungkinan keadaan internal berubah di luar kode Anda. Seperti yang mereka katakan - optimalkan yang terakhir.Tidak digunakan
copy
. Jika kelas Anda benar-benar tidak dapat diubah maka praktik terbaik untuk menerapkanNSCopying
protokol untuk membuat kelas Anda kembali sendiri ketikacopy
digunakan. Jika kamu melakukan ini:copy
.copy
penjelasan membuat kode Anda sendiri lebih dipertahankan - yangcopy
penjelasan menunjukkan bahwa Anda benar-benar tidak perlu khawatir tentang objek ini mengubah negara tempat lain.sumber
Saya mencoba mengikuti aturan sederhana ini:
Apakah saya ingin mempertahankan nilai objek pada titik waktu ketika saya menugaskannya ke properti saya? Gunakan salinan .
Apakah saya ingin berpegang pada objek dan saya tidak peduli apa nilai internal saat ini atau di masa depan? Gunakan yang kuat (pertahankan).
Sebagai ilustrasi: Apakah saya ingin berpegang pada nama "Lisa Miller" ( copy ) atau saya ingin berpegang pada orang yang bernama Lisa Miller ( kuat )? Namanya mungkin kemudian berubah menjadi "Lisa Smith", tetapi dia akan tetap menjadi orang yang sama.
sumber
Melalui contoh ini salin dan simpan dapat dijelaskan seperti:
jika properti itu tipe copy maka,
salinan baru akan dibuat untuk
[Person name]
string yang akan menampung kontensomeName
string. Sekarang setiap operasi padasomeName
string tidak akan berpengaruh[Person name]
.[Person name]
dansomeName
string akan memiliki alamat memori yang berbeda.Tetapi dalam hal mempertahankan,
keduanya
[Person name]
akan memiliki alamat memori yang sama dengan string somename, hanya jumlah penahan string somename yang akan bertambah 1.Jadi setiap perubahan dalam string nama wanita akan tercermin dalam
[Person name]
string.sumber
Tentunya menempatkan 'copy' pada deklarasi properti terbang di muka menggunakan lingkungan berorientasi objek di mana objek pada heap dilewatkan dengan referensi - salah satu manfaat yang Anda dapatkan di sini adalah bahwa, ketika mengubah suatu objek, semua referensi ke objek itu lihat perubahan terbaru. Banyak bahasa yang menyediakan kata kunci 'ref' atau sejenis untuk memungkinkan tipe nilai (yaitu struktur di stack) mendapat manfaat dari perilaku yang sama. Secara pribadi, saya akan menggunakan salinan hemat, dan jika saya merasa bahwa nilai properti harus dilindungi dari perubahan yang dilakukan pada objek tempat ia ditugaskan, saya bisa memanggil metode salin objek itu selama penugasan, misalnya:
Tentu saja, ketika mendesain objek yang berisi properti itu, hanya Anda yang akan tahu apakah desain mendapat manfaat dari pola tempat penugasan mengambil salinan - Cocoawithlove.com memiliki yang berikut ini untuk mengatakan:
"Anda harus menggunakan copy accessor ketika parameter setter mungkin bisa berubah tetapi Anda tidak bisa mengubah status internal suatu properti tanpa peringatan " - jadi penilaian apakah Anda dapat mempertahankan nilai untuk berubah secara tak terduga adalah milik Anda sendiri. Bayangkan skenario ini:
Dalam hal ini, tanpa menggunakan salinan, objek kontak kami mengambil nilai baru secara otomatis; jika kami menggunakannya, kami harus memastikan secara manual bahwa perubahan terdeteksi dan disinkronkan. Dalam hal ini, mempertahankan semantik mungkin diinginkan; di tempat lain, salinan mungkin lebih sesuai.
sumber
sumber
Anda harus menggunakan copy setiap saat untuk mendeklarasikan properti NSString
Anda harus membaca ini untuk informasi lebih lanjut tentang apakah ia mengembalikan string yang tidak dapat diubah (jika string yang dapat diubah dilewati) atau mengembalikan string yang dipertahankan (jika string yang tidak dapat diubah telah dilewatkan)
Referensi Protokol NSCopying
Nilai Objek
sumber
Karena nama adalah (tidak dapat diubah)
NSString
, salin atau simpan tidak ada bedanya jika Anda menetapkanNSString
nama yang lain. Dengan kata lain, salin berperilaku seperti mempertahankan, meningkatkan jumlah referensi satu. Saya pikir itu adalah optimasi otomatis untuk kelas yang tidak dapat diubah, karena mereka tidak dapat diubah dan tidak perlu dikloning. Tetapi ketika aNSMutalbeString
mstr
diatur ke nama, kontenmstr
akan disalin demi kebenaran.sumber
Jika string sangat besar maka salinan akan mempengaruhi kinerja dan dua salinan string besar akan menggunakan lebih banyak memori.
sumber