Apakah ada fungsi bawaan yang memungkinkan saya untuk menyalin secara mendalam NSMutableArray
?
Saya melihat sekeliling, beberapa orang mengatakan [aMutableArray copyWithZone:nil]
karya sebagai salinan dalam. Tapi saya mencoba dan tampaknya salinan yang dangkal.
Saat ini saya melakukan penyalinan secara manual dengan for
loop:
//deep copy a 9*9 mutable array to a passed-in reference array
-deepMuCopy : (NSMutableArray*) array
toNewArray : (NSMutableArray*) arrayNew {
[arrayNew removeAllObjects];//ensure it's clean
for (int y = 0; y<9; y++) {
[arrayNew addObject:[NSMutableArray new]];
for (int x = 0; x<9; x++) {
[[arrayNew objectAtIndex:y] addObject:[NSMutableArray new]];
NSMutableArray *aDomain = [[array objectAtIndex:y] objectAtIndex:x];
for (int i = 0; i<[aDomain count]; i++) {
//copy object by object
NSNumber* n = [NSNumber numberWithInt:[[aDomain objectAtIndex:i] intValue]];
[[[arrayNew objectAtIndex:y] objectAtIndex:x] addObject:n];
}
}
}
}
tapi saya ingin solusi yang lebih bersih, lebih ringkas.
objective-c
cocoa-touch
cocoa
nsarray
deep-copy
ivanTheTerrible
sumber
sumber
-copy
pada koleksi yang tidak dapat diubah berubah antara Mac OS X 10.4 dan 10.5: developer.apple.com/library/mac/releasenotes/Cocoa/… (gulir ke bawah ke "Koleksi yang tidak dapat diubah dan perilaku penyalinan")copy
, apa yang harus dimasukkan ke dalam "salinan dalam"? Jika elemennya adalah koleksi lain,copy
tidak benar-benar menghasilkan salinan (dari kelas yang sama). Jadi saya pikir sangat valid untuk berdebat tentang jenis salinan yang diinginkan dalam kasus tertentu.NSCopying
/-copy
, maka elemen itu tidak dapat disalin — jadi Anda tidak boleh mencoba membuat salinannya, karena itu bukanlah kemampuan yang dirancang untuk dimilikinya. Dalam hal penerapan Cocoa, objek yang tidak dapat disalin sering kali memiliki beberapa status backend C yang terkait dengannya, jadi meretas salinan langsung objek dapat menyebabkan kondisi balapan atau lebih buruk. Jadi untuk menjawab "apa yang harus dimasukkan ke dalam 'salinan dalam'" - A dipertahankan ref. Satu-satunya benda yang dapat Anda letakkan di mana saja jika Anda memiliki non-NSCopying
objek.Jawaban:
Seperti dokumentasi Apple tentang deep copy secara eksplisit menyatakan:
Kode di atas membuat array baru yang anggotanya merupakan salinan dangkal dari anggota array lama.
Perhatikan bahwa jika Anda perlu menyalin secara mendalam seluruh struktur data bersarang - yang oleh dokumen Apple tertaut disebut sebagai salinan dalam yang benar - maka pendekatan ini tidak akan cukup. Silakan lihat jawaban lain di sini untuk itu.
sumber
copyWithZone:
diimplementasikan pada kelas penerima.Satu-satunya cara yang saya tahu untuk melakukan ini dengan mudah adalah dengan mengarsipkan dan kemudian segera membatalkan pengarsipan array Anda. Rasanya seperti sedikit peretasan, tetapi sebenarnya secara eksplisit disarankan dalam Dokumentasi Apple tentang menyalin koleksi , yang menyatakan:
Tangkapannya adalah bahwa objek Anda harus mendukung antarmuka NSCoding, karena ini akan digunakan untuk menyimpan / memuat data.
Versi Swift 2:
sumber
initWithArray:copyItems:
metode ini? Solusi pengarsipan / pengarsipan ini tampaknya sangat berguna, mengingat berapa banyak kelas kontrol yang sesuai dengan NSCoding tetapi tidak dengan NSCopying.Salinan secara default memberikan salinan yang dangkal
Itu karena memanggil
copy
sama dengan yangcopyWithZone:NULL
juga dikenal sebagai menyalin dengan zona default. Thecopy
panggilan tidak menghasilkan salinan yang mendalam. Dalam kebanyakan kasus, ini akan memberi Anda salinan yang dangkal, tetapi dalam hal apa pun itu tergantung pada kelasnya. Untuk diskusi menyeluruh, saya merekomendasikan Topik Pemrograman Koleksi di situs Pengembang Apple.initWithArray: CopyItems: memberikan salinan dalam satu tingkat
NSCoding
adalah cara yang disarankan Apple untuk memberikan salinan dalamUntuk salinan dalam yang benar (Array of Arrays) Anda perlu
NSCoding
dan mengarsipkan / membatalkan pengarsipan objek:sumber
Untuk Dictonary
NSMutableDictionary *newCopyDict = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)objDict, kCFPropertyListMutableContainers);
Untuk Array
NSMutableArray *myMutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(NULL, arrData, kCFPropertyListMutableContainersAndLeaves);
sumber
Tidak, tidak ada sesuatu yang dibangun ke dalam kerangka untuk ini. Koleksi kakao mendukung salinan dangkal (dengan metode
copy
atauarrayWithArray:
) tetapi bahkan tidak berbicara tentang konsep salinan mendalam.Ini karena "salinan dalam" mulai menjadi sulit untuk didefinisikan saat konten koleksi Anda mulai menyertakan objek khusus Anda sendiri. Apakah "salinan dalam" berarti setiap objek dalam grafik objek merupakan referensi unik yang berhubungan dengan setiap objek dalam grafik objek asli?
Jika ada beberapa
NSDeepCopying
protokol hipotetis , Anda dapat mengatur ini dan membuat keputusan di semua objek Anda, tetapi sayangnya tidak ada. Jika Anda mengontrol sebagian besar objek dalam grafik, Anda dapat membuat protokol ini sendiri dan mengimplementasikannya, tetapi Anda perlu menambahkan kategori ke kelas Foundation seperlunya.Jawaban @ AndrewGrant yang menyarankan penggunaan pengarsipan / pembongkaran kunci adalah cara yang tidak berkinerja baik tetapi benar dan bersih untuk mencapai hal ini untuk objek sewenang-wenang. Buku ini bahkan melangkah lebih jauh sehingga menyarankan untuk menambahkan kategori ke semua objek yang melakukan persis seperti itu untuk mendukung penyalinan mendalam.
sumber
Saya memiliki solusi jika mencoba mendapatkan salinan dalam untuk data yang kompatibel dengan JSON.
Hanya mengambil
NSData
dariNSArray
menggunakanNSJSONSerialization
dan kemudian menciptakan JSON Object, ini akan membuat salinan baru dan segar lengkapNSArray/NSDictionary
dengan referensi memori baru dari mereka.Tetapi pastikan objek NSArray / NSDictionary dan anak-anaknya harus dapat bersambung JSON.
sumber
NSJSONReadingMutableContainers
kasus penggunaan dalam pertanyaan ini.