2013-02-13 16 views

Odpowiedz

23

Który z nich jest szybszy?

Nie martw się o to. Przedwczesna optymalizacja.

Główna różnica: pierwsze podejście skutkuje autoreleased "copy", którego nie posiadasz i nie musisz zwolnić, podczas gdy jesteś właścicielem obiektu utworzonego w drugim wierszu. Obie tablice będą niezmienne, przy okazji.

+0

Co z ARC? –

+0

Powiedziałbym, że z ARC używamy drugiego, więc nie jest autoreleased, a zatem nie jest przechowywany dopóki pula autorelease nie zostanie przepłukana. Ale znowu, jeśli nie tworzysz wielu tablic wewnątrz tego samego runloopa (lub wewnątrz @ autoreleasepool), to jest przedwczesna optymalizacja :) –

1

Jedna z nich jest prawdopodobnie szybsza. Uruchom je milion razy i zobacz, czy ktoś wygrywa.

W przypadku NSArray kontra NSMutableArray, kopiowana niezmienna tablica nie musi zwracać kopii, ponieważ nie może się zmienić. Jeśli jednak macie tablicę, którą można zmienić, trzeba ją skopiować, ponieważ można zmienić oryginał. I oczywiście robienie kopii zawsze musi zwrócić nowy obiekt.

W całej aplikacji różnica prędkości i pamięci prawdopodobnie nie będzie miała większego znaczenia niż wszystko inne, co się dzieje.

7

Różnica między tymi dwoma polega na tym, że ta ostatnia zostanie zachowana. Ta pierwsza zostanie autoreleased.

Obie wersje tworzą płytką kopię tablicy.

NSMutableArray *notMutableReally = [NSArray arrayWithArray:aMutableArray]; 

powinno dać ostrzeżenie kompilatora jak będzie próbował przypisać NSArray do NSMutableArray.

Użyj.

NSMutableArray *mutableArrayCopy = [NSMutableArray arrayWithArray:aMutableArray]; 

Który jest szybszy? Nie martw się, wszystkie są o wiele szybsze niż reszta rzeczy, które będziesz robić. Sprawdź z Instruments, czy naprawdę Ci zależy.

4

Główną różnicą jest to, że -copy wie lepiej jak kopiuje się (można to zrobić bardziej efektywnie, a może użyć bardziej dostosowaną podklasę NSArray) podczas +arrayWithArray: stworzy nową instancję NSArray (dobrze, w rzeczywistości używany beton klasy przez Foundation for arrays) i karmić go tą samą listą obiektów z początkowego obiektu. Dodaje także dodatkową autorelease.

Tak więc -copy jest (bardzo bardzo) prawdopodobnie bardziej wydajne.

W rzeczywistości za niezmienny NSArrays, -copy po prostu robi -retain, więc nawet nie przeszkadza tworzenie nowej instancji.

+0

To nie jest dokładne. Podczas tworzenia kopii tworzy się nowa tablica. – thierryb

+1

Możesz wypróbować to za pomocą prostego narzędzia testowego (nie wspominając o tym, że mam inne bardzo dobre powody, by sądzić, że mam rację). – Julien

+0

@Julien, ponieważ wydajesz się bardzo dobrze zorientowany w klasach Foundation, jaki jest właściwy sposób sprawdzania, czy NSArray , NSDictionary itp. Jest zmienne? były już dyskusje gdzie indziej, ale nie znalazłem dobrej odpowiedzi? (-isKindOfClass: mówi się, że nie jest wiarygodny, nie jestem pewien o -respondsToSelector: @selector (addObject :) stuff?) szukając właściwego sposobu ... dzięki! –

21

W uzupełnieniu do innych odpowiedzi, również pamiętać, że gdy someArray jest zerowa, pierwsza linia pozwoli array wskaż pustą tablicę, a drugi zrobi skierować go do zera. Może to być ważna różnica, szczególnie w tablicach zmiennych.

3
NSMutableArray *arr = [NSMutableArray array]; 
for (int i = 0; i < 10000; i ++) 
{ 
    [arr addObject:@(i*1000000ULL)]; 
} 
// MARK 
// arr = (id)[NSArray arrayWithArray:arr]; 

NSTimeInterval t = [NSDate timeIntervalSinceReferenceDate]; 
NSArray *res = nil; 
for (int i = 0; i < 10000; i ++) 
{ 
    res = [arr copy]; 
} 
NSLog(@"time A: %f", [NSDate timeIntervalSinceReferenceDate] - t); 
t = [NSDate timeIntervalSinceReferenceDate]; 
for (int i = 0; i < 10000; i ++) 
{ 
    res = [NSArray arrayWithArray:arr]; 
} 
NSLog(@"time B: %f", [NSDate timeIntervalSinceReferenceDate] - t); 

czas A: 1,572795 czas B: 1,539150 B [NSArray arrayWithArray:] zawsze szybciej, ale różnica w czasie bardzo małe. Ale jeśli odkomentowaniu „Mark” i się skopiować z NSArray zamiast NSMutableArray będziemy mieć inne wykonania A: 0,000473 B Czas: 1.548400 wynik: ~ 3200x razy szybciej

1

W Swifta, to jest zupełnie inna. Dzięki nowej Open Source Foundation dla Swift wiemy, że podczas gdy init(array:) tworzy nową tablicę z podanymi przedmiotami (jeśli są), po prostu zwraca self.

public override func copy() -> AnyObject { 
     return copyWithZone(nil) 
    } 

    public func copyWithZone(zone: NSZone) -> AnyObject { 
     return self 
    } 

https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSArray.swift#L82

public convenience init(array: [AnyObject]) { 
     self.init(array: array, copyItems: false) 
    } 

    public convenience init(array: [AnyObject], copyItems: Bool) { 
     let optionalArray : [AnyObject?] = 
      copyItems ? 
       array.map { return Optional<AnyObject>(($0 as! NSObject).copy()) } : 
       array.map { return Optional<AnyObject>($0) } 

     // This would have been nice, but "initializer delegation cannot be nested in another expression" 
//  optionalArray.withUnsafeBufferPointer { ptr in 
//   self.init(objects: ptr.baseAddress, count: array.count) 
//  } 
     let cnt = array.count 
     let buffer = UnsafeMutablePointer<AnyObject?>.alloc(cnt) 
     buffer.initializeFrom(optionalArray) 
     self.init(objects: buffer, count: cnt) 
     buffer.destroy(cnt) 
     buffer.dealloc(cnt) 
    } 

https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSArray.swift#L116

Tak, oczywiście, copy() jest szybsza, a teraz wiesz, jak oboje pracy! (Tylko w Swift)

+1

Dobrze wiedzieć, jak to działa w Swift :) –