Bagaimana cara mengubah NSMutableArray ke NSArray?


Jawaban:


511
NSArray *array = [mutableArray copy];

Copymembuat salinan yang tidak dapat diubah. Ini cukup berguna karena Apple dapat melakukan berbagai optimasi. Misalnya mengirim copyke array yang tidak dapat diubah hanya mempertahankan objek dan kembali self.

Jika Anda tidak menggunakan pengumpulan sampah atau ARC ingat bahwa -copymempertahankan objek.


2
jawaban ini bagus, tetapi bagaimana saya bisa tahu dari dokumen yang copymenciptakan NSArray normal dan bukan NSMutableArray?
Dan Rosenstark

22
@ Yar: Anda melihat dokumentasi NSCopying yang menyatakan di sana: copyWithZone Salinan yang dikembalikan tidak dapat diubah jika pertimbangan "tidak berubah vs berubah" berlaku untuk objek penerima; jika tidak, sifat tepat dari salinan ditentukan oleh kelas.
Georg Schölly

1
Sangat rapi - Saya lebih suka solusi ini dari m5h. Keduanya singkat dan lebih efisien.
David Snabel-Caunt

1
Saya setuju David, memperbarui tanggapan saya untuk menunjukkan tanggapan ini.
hallski

2
@Rad: Itu hanya berarti kelas yang memiliki implementasi yang bisa berubah dan tidak dapat diubah. Mis. NSArray& NSMutableArray, NSString& NSMutableString. Tapi tidak misalnya NSViewControlleryang selalu berisi keadaan bisa berubah.
Georg Schölly

361

An NSMutableArrayadalah subkelas NSArraysehingga Anda tidak perlu selalu mengonversi tetapi jika Anda ingin memastikan bahwa array tidak dapat dimodifikasi, Anda dapat membuat NSArraysalah satu dari cara ini tergantung pada apakah Anda ingin autoreleased atau tidak:

/* Not autoreleased */
NSArray *array = [[NSArray alloc] initWithArray:mutableArray];

/* Autoreleased array */
NSArray *array = [NSArray arrayWithArray:mutableArray];

EDIT: Solusi yang disediakan oleh Georg Schölly adalah cara yang lebih baik untuk melakukannya dan jauh lebih bersih, terutama sekarang kita memiliki ARC dan bahkan tidak perlu memanggil autorelease.


7
Bisakah saya melakukan (NSArray *) myMutableArray?
Vojto

2
Ya, karena NSMutableArray adalah subkelas dari NSArray yang valid.
hallski

4
Namun, casting ke (NSArray *) masih memungkinkan cast kembali ke (NSMutable *). Bukankah begitu?
Sharar

1
@ Sharvey: Ya, itu benar. Anda akan mendapatkan peringatan jika Anda tidak melakukan cast tetapi langsung menugaskan superclass ke subclass. Biasanya, Anda ingin mengembalikan salinan yang tidak dapat diubah, karena itulah satu-satunya cara untuk memastikan, bahwa array Anda benar-benar tidak akan dimodifikasi.
Georg Schölly

1
Sebelumnya Itu dikenal sebagai "Upcasting" (NSArray *) myMutableArray dan kebalikannya disebut "Downcasting"
Francisco Gutiérrez

113

Saya menyukai kedua solusi utama:

NSArray *array = [NSArray arrayWithArray:mutableArray];

Atau

NSArray *array = [mutableArray copy];

Perbedaan utama yang saya lihat di dalamnya adalah bagaimana mereka berperilaku ketika mutableArray nihil :

NSMutableArray *mutableArray = nil;
NSArray *array = [NSArray arrayWithArray:mutableArray];
// array == @[] (empty array)

NSMutableArray *mutableArray = nil;
NSArray *array = [mutableArray copy];
// array == nil

Ini sangat salah. Baru diperiksa. [mutableArray copy] juga mengembalikan array kosong.
durazno

@durazno Tidak salah. Periksa tes Anda. Jika [mutableArray copy] mengembalikan array kosong, maka mutableArray pastilah array kosong. Jawaban saya hanya berlaku ketika mutableArray nihil.
Richard Venable

Meskipun ini benar, saya merasa Anda kehilangan kebenaran yang lebih mendasar dalam contoh Anda. Karena Anda telah menetapkan mutableArray sebagai nil, [mutableArray copy]dapat disederhanakan menjadi [nil copy]. Dalam tujuan-c setiap pesan yang dikirim ke nil akan selalu nihil. Sangat penting untuk mengingat perbedaan antara "tidak ada" dan "array tanpa apa pun di dalamnya".
mkirk

@ mkirk Jangan mengalihkan perhatian dari pertanyaan: "Bagaimana cara saya mengkonversi NSMutableArray ke NSArray?" Ada 2 solusi utama, dan perbedaan utama di antara mereka adalah bagaimana mereka berperilaku ketika array bisa berubah nihil.
Richard Venable

18

Anda mencoba kode ini ---

NSMutableArray *myMutableArray = [myArray mutableCopy];

dan

NSArray *myArray = [myMutableArray copy];

Apa yang dilakukan yang tidak dilakukan orang lain?
Ben Leggiero

5

Objektif-C

Di bawah ini adalah cara untuk mengkonversi NSMutableArray ke NSArray:

//oldArray is having NSMutableArray data-type.
//Using Init with Array method.
NSArray *newArray1 = [[NSArray alloc]initWithArray:oldArray];

//Make copy of array
NSArray *newArray2 = [oldArray copy];

//Make mutablecopy of array
NSArray *newArray3 = [oldArray mutableCopy];

//Directly stored NSMutableArray to NSArray.
NSArray *newArray4 = oldArray;

Cepat

Di Swift 3.0 ada tipe data baru Array . Deklarasikan Array menggunakan letkata kunci maka akan menjadi NSArray Dan jika menyatakan menggunakan varkata kunci maka itu menjadi NSMutableArray .

Kode sampel:

let newArray = oldArray as Array

Bagian Swift tidak sepenuhnya benar. Lihat di sini dan di sini untuk perbedaan antara bisa berubah / tidak berubah Arraydan NSArray/ NSMutableArrays. Mereka tidak sama.
Bruno Ely

3

Dalam tujuan-c:

NSArray *myArray = [myMutableArray copy];

Dengan cepat:

 var arr = myMutableArray as NSArray

2
NSArray *array = mutableArray;

[mutableArray copy]Antipattern ini adalah seluruh kode sampel. Berhentilah melakukannya untuk array yang dapat dipindahkan yang sementara yang transien dan dapatkan deallocated pada akhir lingkup saat ini.

Tidak ada cara runtime dapat mengoptimalkan pemborosan dari array yang bisa berubah yang baru saja akan keluar dari ruang lingkup, didekomposisi menjadi 0 dan dialokasikan untuk selamanya.


Menetapkan suatu NSMutableArrayke suatu NSArrayvariabel tidak akan menyamarkannya (yang merupakan pertanyaan OP tentang). Mengekspos nilai seperti itu (misalnya sebagai nilai balik atau sebagai properti) dapat mengakibatkan masalah yang sangat sulit untuk di-debug jika nilai itu secara tak terduga bermutasi. Ini berlaku untuk mutasi internal dan eksternal karena nilai yang dapat diubah dibagikan.
David Rönnqvist

Untuk menonaktifkan array itu, Anda harus [NSMutableArray arrayWithArray: ... atau sesuatu seperti itu.
Anton Tropashko

Belum tentu. Cukup dengan menugaskannya ke NSMutableArrayvariabel sudah cukup. Karena objek tidak pernah berhenti menjadi array yang dapat diubah, memanggil metode yang bermutasi padanya akan berhasil dan mengubah data yang dibagikan. Jika di sisi lain array yang dapat diubah asli disalin — mengubahnya ke array yang tidak dapat diubah - dan kemudian ditugaskan ke NSMutableArrayvariabel dan memiliki metode mutasi yang memanggilnya, panggilan tersebut akan gagal dengan doesNotRespondToSelectorkesalahan karena objek yang menerima panggilan metode mutasi ada di Bahkan tidak berubah dan tidak menanggapi metode-metode itu.
David Rönnqvist

ok, ini mungkin memiliki beberapa manfaat bagi pengembang yang tidak mengindahkan kompiler yang memperingatkan tentang tugas konversi tyope
Anton Tropashko

1

Jika Anda membuat array melalui mutabilitas dan kemudian ingin mengembalikan versi yang tidak dapat diubah, Anda bisa mengembalikan array yang bisa diubah sebagai "NSArray" melalui pewarisan.

- (NSArray *)arrayOfStrings {
    NSMutableArray *mutableArray = [NSMutableArray array];
    mutableArray[0] = @"foo";
    mutableArray[1] = @"bar";

    return mutableArray;
}

Jika Anda "mempercayai" penelepon untuk memperlakukan objek kembali (secara teknis masih bisa berubah) sebagai NSArray yang tidak berubah, ini adalah opsi yang lebih murah daripada [mutableArray copy].

Apple setuju:

Untuk menentukan apakah itu dapat mengubah objek yang diterima, penerima pesan harus bergantung pada tipe formal nilai pengembalian. Jika ia menerima, misalnya, objek array yang diketik sebagai tidak dapat diubah, ia tidak boleh mencoba untuk mengubahnya . Ini bukan praktik pemrograman yang dapat diterima untuk menentukan apakah suatu objek dapat diubah berdasarkan keanggotaan kelasnya.

Praktik di atas dibahas secara lebih rinci di sini:

Praktik Terbaik: Kembalikan mutableArray.copy atau mutableArray jika jenis kembali adalah NSArray


0

saya sedang mencari jawaban di swift 3 dan pertanyaan ini ditunjukkan sebagai hasil pertama dalam pencarian dan saya mendapatkan inspirasi jawabannya dari itu jadi di sini adalah kode 3 cepat

let array: [String] = nsMutableArrayObject.copy() as! [String]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.