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.
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.
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”
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.
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 arrayNSArray*newArray2 =[oldArray copy];//Make mutablecopy of arrayNSArray*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 .
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.
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.
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.
Jeśli „zaufasz” dzwoniącemu do traktowania (zwracanego technicznie wciąż zmiennego) obiektu zwrotnego jako niezmiennego NSArray, jest to tańsza opcja niż [mutableArray copy] .
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:
NSArray *array = [mutableArray copy];
NSArray *array = mutableArray;
Odpowiedzi:
Copy
wykonuje niezmienne kopie. Jest to bardzo przydatne, ponieważ Apple może dokonywać różnych optymalizacji. Na przykład wysłaniecopy
do niezmiennej tablicy zachowuje tylko obiekt i zwracaself
.Jeśli nie używasz śmiecia lub ARC pamiętaj, że
-copy
zachowuje obiekt.źródło
copy
tworzą normalny NSArray, a nie NSMutableArray?NSArray
&NSMutableArray
,NSString
&NSMutableString
. Ale nie na przykład,NSViewController
który zawsze zawiera stan zmienny.An
NSMutableArray
jest podklasą,NSArray
więc nie zawsze będziesz musiał konwertować, ale jeśli chcesz się upewnić, że tablica nie może zostać zmodyfikowana, możesz utworzyćNSArray
jeden z tych sposobów, w zależności od tego, czy chcesz ją automatycznie wydać, czy nie: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.
źródło
Lubię oba z dwóch głównych rozwiązań:
Lub
Podstawowa różnica widzę w nich jest to, jak się zachowują, gdy mutableArray jest zerowa :
źródło
[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”.próbujesz tego kodu ---
i
źródło
Cel C
Poniżej znajduje się sposób na konwersję NSMutableArray na NSArray:
Szybki
W Swift 3.0 wprowadzono nowy typ danych Array . Zadeklaruj tablicę za pomocą
let
słowa kluczowego, a następnie stanie się NSArray. Jeśli zadeklarujesz użycievar
słowa kluczowego, stanie się NSMutableArray .Przykładowy kod:
źródło
Array
siNSArray
/NSMutableArray
s. One nie są takie same.W celu c:
W krótkim:
źródło
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.
źródło
NSMutableArray
doNSArray
zmiennej 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.NSMutableArray
zmiennej. 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 doNSMutableArray
zmiennej i wywołano w niej metody mutacji, wywołania te zakończyłyby siędoesNotRespondToSelector
błędami, ponieważ obiekt, który otrzymał wywołanie metody mutacji, znajduje się w fakt niezmienny i nie reaguje na te metody.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.
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ę:
Powyższą praktykę omówiono bardziej szczegółowo tutaj:
Najlepsza praktyka: Zwróć mutableArray.copy lub mutableArray, jeśli typem zwrotu jest NSArray
źródło
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
źródło