2010-01-03 9 views
5

Aby zoptymalizować wąskie gardło, skonwertowałem tworzenie dużej tablicy NSArray na tablicę w stylu c. (Wynikowa kreacja była 1/8 czasu oryginalnej wersji NSArray.) Taa!) Ale kiedy już jest tworzona, prędkość nie jest już problemem, więc wolałbym znowu skorzystać z tego, że jest to NSArray.Musi być łatwiejszy sposób radzenia sobie z tablicami!

Jednak wydaje się absurdalnie zaangażowany przekonwertować tablicy c stylu do NSArray (chyba brakuje mi jakiś magiczny sposób initWithArrayWrapElementsInObjects.)

Jak rozumiem proces teraz, najpierw trzeba utworzyć NSMutableArray , iteruj przez macierz w stylu c, konwertując każdy element (pływa w moim przypadku) do obiektów, dodając każdy obiekt do NSMutableArray, a następnie tworząc NSArray z NSMutableArray.

Czy to prawda? Musi być lepszy sposób.

Pomoc byłaby doceniona.

Dzięki!

Odpowiedz

7

Nie ma bezpośredniego sposobu na zrobienie kropli pamięci, którą posiadasz, i "konwersję" jej taniej na NSArray - w końcu ramy będą musiały posiadać tę pamięć, a ona nie wie, gdzie jesteś to z (malloc, stack, itp.). Gdyby istniała wygodna metoda dla initWithArrayWrapElementsInObjects, sama musiałaby wewnętrznie przewidzieć, co się domyśla: iterować po dostarczonej pamięci i dodawać elementy do siebie (prawdopodobnie framework mógłby to zrobić tak szybko, jak memcpy, ale kto wie).

Jednym ze sposobów poradzenia sobie z tym (i prawdopodobnie zabawnym ćwiczeniem) jest stworzenie własnej podklasy NSArray, która zarządza pamięcią dokładnie tak, jak chcesz (np. Pozwala tworzyć i uruchamiać dowolną semantykę), ale który zachowuje się do zewnętrznego świata, tak jak zrobiłby to NSArray. Możesz to zrobić, dziedzicząc z NSArray i implementując metody, które będą działać na dowolnej pamięci, na którą się trzymasz. Oczywiście, musisz również zaimplementować zarządzanie własną pamięcią w metodach init/dealloc, etc. Zobacz tę stronę http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html w "Uwagi dotyczące podkatalogów".

Dyskusja na temat projektu zależy od tego, jakie są Twoje dane. NSArray, oczywiście, oczekuje, że jego elementy będą referencjami Obj-C (typu id), a nie tylko dowolnymi porcjami danych. Jeśli twoja tablica w stylu C trzyma struktury lub inne prymitywne wartości, które nie są odniesieniami do obiektów, technika ta nie będzie działać dla ciebie - interfejs NSArray nigdy nie będzie zadowolony z elementów niezwiązanych z referencjami.

Ostatnia uwaga: wspomniałeś o wzięciu NSMutableArray i "stworzeniu" NSArray razem z nim. Należy mieć świadomość, że NSMutableArray jest już NSArray, ponieważ jest to podklasa. Możesz użyć instancji NSMutableArray w dowolnym miejscu, gdzie chcesz NSArray, bez tworzenia nowej kopii.

UPDATE: Pominięto notatkę o macierzy zawierającej zmienne. Tak, jesteś tu trochę zakręcony. NSArrays chce obiektów. Jeśli podwojenie wydajności było kosztowną częścią (jak zauważa inny plakat), spróbuj initWithCapacity :. Jeśli chodzi o boksowanie/rozpakowywanie paczek do typów obiektów, nic nie możesz zrobić.

Stworzyłem (ale nie mam pod ręką) parę bardzo prostych klas (zwanych jak MYArray i MYMutableArray), które są przeznaczone do zawijania właśnie tego rodzaju danych za pomocą metod NSArray na nich. Ale nie są one zamienne z NSArrays. Musisz ich użyć celowo.

AKTUALIZACJA # 2. Wiem, że minęły wieki od czasu, gdy to pytanie było na żywo, ale po prostu ponownie je przeanalizowałem i zdałem sobie sprawę, że w tym konkretnym przypadku jest to dość sprytny sposób. (Chcesz niezmiennego NSArray z macierzy float w stylu C). Możesz utworzyć niestandardową podklasę NSArray, która opakowuje wartości zmiennoprzecinkowe i konwertuje je tylko do obiektów, gdy są one dostępne przez prymitywy. Może to mieć pułapki wydajnościowe w niektórych zakątkach (?), Ale spełnia dokładnie Twoje wymagania:

@interface FloatProxyArray : NSArray 
{ 
    float * values; 
    NSUInteger count; 
} 
- (id)initWithCArray:(float *)arrayOfFloats count:(int)numberOfValues; 
@end 

.

@implementation FloatProxyArray 
- (id)initWithCArray:(float *)arrayOfFloats count:(int)numberOfValues 
{ 
    if ((self = [super init])) { 
     values = (float *)malloc(numberOfValues * sizeof(float)); 
     if (!values) { 
      [self release]; return nil; 
     } 
     memcpy(values, arrayOfFloats, numberOfValues * sizeof(float)); 
     count = numberOfValues; 
    } 
    return self; 
} 

- (void)dealloc 
{ 
    free(values); 
    [super dealloc] 
} 

- (NSUInteger)count 
{ 
    return count; 
} 

- (id)objectAtIndex:(NSUInteger)index 
{ 
    if (index >= count) { 
     [NSException raise:NSRangeException format:@""]; 
     return nil; 
    } 

    float val = values[index]; 
    return [NSNumber numberWithFloat:val]; 
} 
@end 

(NB pisane w edytorze bez kompilowania/testowanie).

+0

Dzięki! To ma sens. –

3

Jeden optymalizacji, które można zrobić z NSMutableArray jest initWithCapacity które będą zapobiegać podwojenie swojej tablicy, która jest kosztowna operacja w dodatku .

Poza tym, ponieważ NSArrays i NSMutableArrays oczekują obiektów, więc trudno to obejść.

0

"Najlepszą" optymalizacją (dla prędkości) byłoby prawie na pewno uniknięcie użycia w miarę możliwości NSArray.

1

Jakie korzyści płyną z tego, że jesteś NSArray, którego szukasz?

Wygląda na to, że lepiej sobie radzić z niestandardowym obiektem otaczającym tablicę C, która odpowiada na wszystkie komunikaty NSArray, które chcesz wywołać. W przeciwnym razie powracasz do punktu tworzenia macierzy ... Możesz spróbować ręcznie utworzyć wywołanie initWithObjects, ale co najmniej każdy float musi być zawinięty w NSNumber, który spowolniłby twoją prędkość.

Jeśli naprawdę potrzebujesz NSArray, ponieważ coś innego, czego chcesz użyć, bierze obiekty NSArray, to prawdopodobnie lepiej jest wyłączyć podklasę NSArray (zgodnie z wytycznymi opublikowanymi przez Bena).

Powiązane problemy