Jak przekonwertować NSMutableArray na NSArray?

381

Jak przekonwertować NSMutableArray na NSArray w ?

marcy
źródło
12
właśnieNSArray *array = [mutableArray copy];
beryl
1
NSArray *array = mutableArray;
vladof81
4
beryl: Absolutnie racja. vladof81: Oczywiście, że nie.
gnasher729

Odpowiedzi:

511
NSArray *array = [mutableArray copy];

Copywykonuje niezmienne kopie. Jest to bardzo przydatne, ponieważ Apple może dokonywać różnych optymalizacji. Na przykład wysłanie copydo niezmiennej tablicy zachowuje tylko obiekt i zwraca self.

Jeśli nie używasz śmiecia lub ARC pamiętaj, że -copyzachowuje obiekt.

Georg Schölly
źródło
2
ta odpowiedź jest świetna, ale jak mogę stwierdzić na podstawie dokumentów, które copytworzą normalny NSArray, a nie NSMutableArray?
Dan Rosenstark
22
@Yar: Patrzysz na dokumentację NSCopying. Tam jest napisane : copyWithZone Zwrócona kopia jest niezmienna, jeśli rozważenie „niezmienny vs. zmienny” dotyczy obiektu odbierającego; w przeciwnym razie dokładny charakter kopii określa klasa.
Georg Schölly,
1
Bardzo fajnie - wolę to od rozwiązania m5h. Zwięzły i bardziej wydajny.
David Snabel-Caunt
1
Zgadzam się, David, zaktualizowałem moją odpowiedź, aby wskazać tę odpowiedź.
hallski
2
@Brad: Oznacza to po prostu klasy, które mają zarówno modyfikowalne, jak i niezmienne implementacje. Np NSArray& NSMutableArray, NSString& NSMutableString. Ale nie na przykład, NSViewControllerktóry zawsze zawiera stan zmienny.
Georg Schölly,
361

An NSMutableArrayjest podklasą, NSArraywięc nie zawsze będziesz musiał konwertować, ale jeśli chcesz się upewnić, że tablica nie może zostać zmodyfikowana, możesz utworzyć NSArrayjeden z tych sposobów, w zależności od tego, czy chcesz ją automatycznie wydać, czy nie:

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

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

EDYCJA: Rozwiązanie dostarczone przez Georga Schölly to lepszy sposób na zrobienie tego i dużo czystsze, szczególnie teraz, gdy mamy ARC i nawet nie musimy wywoływać automatycznego wydawania.

Hallski
źródło
7
Czy mogę po prostu zrobić (NSArray *) myMutableArray?
Vojto,
2
Tak, ponieważ NSMutableArray jest podklasą NSArray, która jest poprawna.
hallski
4
Jednak rzutowanie na (NSArray *) nadal pozwala rzutować z powrotem na (NSMutable *). Czy tak nie jest?
sharvey
1
@sharvey: Tak, to prawda. Otrzymasz ostrzeżenie, jeśli nie rzucisz, ale bezpośrednio przypiszesz nadklasę do podklasy. Zwykle chcesz zwrócić niezmienną kopię, ponieważ jest to jedyny sposób, aby mieć pewność, że twoja tablica naprawdę nie zostanie zmodyfikowana.
Georg Schölly,
1
Dawniej Znany jako „Upcasting” (NSArray *) myMutableArray, a odwrotność nazywa się „Downcasting”
Francisco Gutiérrez
113

Lubię oba z dwóch głównych rozwiązań:

NSArray *array = [NSArray arrayWithArray:mutableArray];

Lub

NSArray *array = [mutableArray copy];

Podstawowa różnica widzę w nich jest to, jak się zachowują, gdy mutableArray jest zerowa :

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

NSMutableArray *mutableArray = nil;
NSArray *array = [mutableArray copy];
// array == nil
Richard Venable
źródło
To takie złe. Właśnie sprawdziłem. [mutableArray copy] zwraca również pustą tablicę.
durazno
@durazno To nie jest źle. Sprawdź dokładnie swój test. Jeśli [mutableArray copy] zwraca pustą tablicę, to mutableArray musi być pustą tablicą. Moja odpowiedź ma zastosowanie tylko wtedy, gdy mutableArray ma wartość zero.
Richard Venable
Chociaż to prawda, wydaje mi się, że w twoim przykładzie brakuje Ci bardziej fundamentalnej prawdy. Ponieważ przypisałeś mutableArray jako zero, [mutableArray copy]można to uprościć [nil copy]. W celu-c każda wiadomość wysłana do zera zawsze będzie zerowa. Ważne jest, aby pamiętać o rozróżnieniu między „niczym” a „tablicą bez niczego”.
mkirk
@mkirk Nie odrywajmy się od pytania: „Jak przekonwertować NSMutableArray na NSArray?” Istnieją 2 podstawowe rozwiązania, a podstawowa różnica między nimi polega na tym, jak zachowują się, gdy tablica zmiennych jest zerowa.
Richard Venable
18

próbujesz tego kodu ---

NSMutableArray *myMutableArray = [myArray mutableCopy];

i

NSArray *myArray = [myMutableArray copy];
Jerry Thomsan
źródło
Co to robi, czego inni nie robią?
Ben Leggiero,
5

Cel C

Poniżej znajduje się sposób na konwersję NSMutableArray na 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;

Szybki

W Swift 3.0 wprowadzono nowy typ danych Array . Zadeklaruj tablicę za pomocą letsłowa kluczowego, a następnie stanie się NSArray. Jeśli zadeklarujesz użycie varsłowa kluczowego, stanie się NSMutableArray .

Przykładowy kod:

let newArray = oldArray as Array
Sakir Sherasiya
źródło
Część Szybka nie jest całkowicie poprawna. Zobacz tutaj i tutaj, aby zobaczyć różnicę między zmiennymi / niezmiennymi Arraysi NSArray/ NSMutableArrays. One nie są takie same.
Bruno Ely,
3

W celu c:

NSArray *myArray = [myMutableArray copy];

W krótkim:

 var arr = myMutableArray as NSArray
Vikram Biwal
źródło
2
NSArray *array = mutableArray;

Ten [mutableArray copy]antywzorzec projektowy jest całym przykładowy kod. Przestań to robić w przypadku rzutowanych zmiennych tablic, które są przejściowe i zostają zwolnione na końcu bieżącego zakresu.

Nie ma możliwości, aby środowisko wykonawcze zoptymalizowało marnotrawstwo kopiowania zmiennej tablicy, która właśnie wychodzi poza zakres, dekrefuje do zera i zostaje na stałe zwolniona.

Anton Tropashko
źródło
Przypisanie zmiennej NSMutableArraydo NSArrayzmiennej nie ukryje jej (o to chodzi w pytaniu PO). Ujawnienie takiej wartości (na przykład jako wartości zwracanej lub jako właściwości) może spowodować bardzo trudne problemy z debugowaniem, jeśli ta wartość zostanie nieoczekiwanie zmutowana. Dotyczy to zarówno wewnętrznych, jak i zewnętrznych mutacji, ponieważ zmienna wartość jest wspólna.
David Rönnqvist,
Aby zmutować tę tablicę, musisz [NSMutableArray arrayWithArray: ... lub coś takiego.
Anton Tropashko,
Niekoniecznie. Wystarczy przypisać ją do NSMutableArrayzmiennej. Ponieważ obiekt nigdy nie przestał być zmienną tablicą, wywołanie na nim metod mutacji zakończy się powodzeniem i zmutuje udostępnione dane. Z drugiej strony, jeśli oryginalna zmienna tablica została skopiowana - zmieniając ją w niezmienną tablicę - a następnie przypisana do NSMutableArrayzmiennej i wywołano w niej metody mutacji, wywołania te zakończyłyby się doesNotRespondToSelectorbłędami, ponieważ obiekt, który otrzymał wywołanie metody mutacji, znajduje się w fakt niezmienny i nie reaguje na te metody.
David Rönnqvist
ok, to może mieć jakąś wartość dla programistów, którzy nie zwracają uwagi na ostrzeżenie kompilatora o przydziałach konwersji tyopów
Anton Tropashko
1

Jeśli konstruujesz tablicę poprzez mutację, a następnie chcesz zwrócić niezmienną wersję, możesz po prostu zwrócić tablicę mutable jako „NSArray” poprzez dziedziczenie.

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

    return mutableArray;
}

Jeśli „zaufasz” dzwoniącemu do traktowania (zwracanego technicznie wciąż zmiennego) obiektu zwrotnego jako niezmiennego NSArray, jest to tańsza opcja niż [mutableArray copy] .

Apple zgadza się:

Aby ustalić, czy może zmienić odebrany obiekt, odbiorca wiadomości musi polegać na formalnym typie zwracanej wartości. Jeśli otrzyma na przykład obiekt tablicy o typie niezmiennym, nie powinien próbować go mutować . Nie jest akceptowalną praktyką programistyczną ustalanie, czy obiekt można modyfikować na podstawie jego przynależności do klasy.

Powyższą praktykę omówiono bardziej szczegółowo tutaj:

Najlepsza praktyka: Zwróć mutableArray.copy lub mutableArray, jeśli typem zwrotu jest NSArray

pkamb
źródło
0

szukałem odpowiedzi w swift 3 i to pytanie pojawiło się jako pierwszy wynik wyszukiwania i zainspirowałem się odpowiedzią, więc oto kod swift 3

let array: [String] = nsMutableArrayObject.copy() as! [String]
Amr Angry
źródło