Tablice asocjacyjne

Flash Player 9 i nowsze wersje, Adobe AIR 1.0 i nowsze wersje

Tablice asocjacyjne, czasami określane jako tablice mieszające lub tablice odwzorowujące , do porządkowania zapisanych wartości używają kluczy , nie zaś indeksu liczbowego. Każdy klucz w tablicy asocjacyjnej jest unikalnym łańcuchem używanym do uzyskiwania dostępu do zapisanych wartości. Tablica asocjacyjna jest instancją klasy Object, co oznacza, że każdy jej klucz odpowiada nazwie właściwości. Tablice asocjacyjne to nieuporządkowane kolekcje par kluczy i wartości. W kodzie opracowywanym przez użytkownika nie powinno znaleźć się ciche założenie, że klucze tablicy asocjacyjnej będą w jakikolwiek sposób uporządkowane.

Język ActionScript 3.0 zawiera też zaawansowany typ tablicy asocjacyjnej określany jako słownik . Słowniki, które są instancjami klasy Dictionary w pakiecie flash.utils, korzystają z kluczy, które mogą mieć dowolny typ danych. Innymi słowy, klucze słowników nie są ograniczone do wartości typu String.

Tablice asocjacyjne z kluczami w postaci łańcucha

Istnieją dwa sposoby tworzenia tablic asocjacyjnych w języku ActionScript 3.0. Pierwszy z nich to użycie instancji Object. Za pomocą instancji klasy Object można zainicjować tablicę z literałem obiektu. Wystąpienie klasy Object, określane również jako obiekt ogólny , jest funkcjonalnie identyczne z tablicą asocjacyjną. Każda nazwa właściwości obiektu generycznego działa jak klucz zapewniający dostęp do zapisanych wartości.

Poniższy przykład ilustruje tworzenie tablicy asocjacyjnej o nazwie monitorInfo za pomocą literału obiektu w celu zainicjowania tablicy za pośrednictwem dwóch par kluczy i wartości.

var monitorInfo:Object = {type:"Flat Panel", resolution:"1600 x 1200"}; 
trace(monitorInfo["type"], monitorInfo["resolution"]);  
// output: Flat Panel 1600 x 1200

Jeśli nie trzeba inicjować tablicy w chwili deklaracji, można użyć konstruktora Object w celu utworzenia tablicy, zgodnie z poniższym przykładem.

var monitorInfo:Object = new Object();

Gdy tablica zostanie utworzona za pomocą literału obiektu lub konstruktora klasy Object, można dodać nowe wartości do tablicy, korzystając z operatora dostępu do klasy ( [] ) lub operatora kropki ( . ). Poniższy przykład ilustruje dodawanie dwóch nowych wartości do zmiennej monitorArray .

monitorInfo["aspect ratio"] = "16:10"; // bad form, do not use spaces 
monitorInfo.colors = "16.7 million"; 
trace(monitorInfo["aspect ratio"], monitorInfo.colors); 
// output: 16:10 16.7 million

Należy pamiętać, że klucz o nazwie aspect ratio zawiera znak spacji. Jest to dopuszczalne w przypadku operatora dostępu do klasy ( [] ), spowoduje jednak wygenerowanie błędu w przypadku próby skorzystania z operatora kropki. Używanie spacji w nazwach kluczy jest w związku z tym niezalecane.

Drugim sposobem na utworzenie tablicy asocjacyjnej jest użycie konstruktora Array (lub konstruktora dowolnej klasy dynamicznej), a następnie użycie operatora dostępu do tablicy ( [] ) albo operatora kropki ( . ) w celu dodania pary klucz plus wartość do tablicy. W przypadku zdeklarowania tablicy asocjacyjnej, która ma być tablicą typu Array, nie można użyć literału obiektowego do inicjalizacji tablicy. Poniższy przykład ilustruje tworzenie tablicy asocjacyjnej o nazwie monitorInfo za pomocą konstruktora klasy Array oraz dodawanie klucza o nazwie type oraz klucza o nazwie resolution , wraz z ich wartościami.

var monitorInfo:Array = new Array(); 
monitorInfo["type"] = "Flat Panel"; 
monitorInfo["resolution"] = "1600 x 1200"; 
trace(monitorInfo["type"], monitorInfo["resolution"]);  
// output: Flat Panel 1600 x 1200

Wykorzystanie do utworzenia tablicy asocjacyjnej konstruktora Array nie przynosi żadnej korzyści. W przypadku tablic asocjacyjnych nie można używać właściwości Array.length ani żadnej z metod klasy Array, nawet jeśli zostanie użyty konstruktor Array lub typ danych Array. Użycie konstruktora Array najlepiej jest pozostawić do czasu utworzenia tablic indeksowanych.

Tablice asocjacyjne z kluczami obiektowymi (Słowniki)

Możliwe jest użycie klasy Dictionary do utworzenia tablicy asocjacyjnej korzystającej z kluczy, nie zaś z łańcuchów. Takie tablice są niekiedy zwane słownikami, tablicami mieszającymi lub mapującymi. Należy na przykład rozważyć aplikację determinującą lokalizację obiektu Sprite opartego na jej powiązaniu z określonym kontenerem. Możliwe jest użycie obiektu Dictionary w celu zmapowania każdego obiektu Sprite do kontenera.

Poniższy kod umożliwia utworzenie trzech instancji klasy Sprite, działających jako klucze dla obiektu Dictionary. Każdemu z kluczy przypisywana jest wartość GroupA lub GroupB . Wartości te mogą być wartościami dowolnego typu danych, lecz w tym przykładzie obie wartości — GroupA i GroupB — są wystąpieniami klasy Object. Następnie można również uzyskać dostęp do wartości skojarzonej z każdym z kluczy za pomocą operatora dostępu do tablicy ( [] ), zgodnie z poniższym przykładowym kodem.

import flash.display.Sprite; 
import flash.utils.Dictionary; 
 
var groupMap:Dictionary = new Dictionary(); 
 
// objects to use as keys 
var spr1:Sprite = new Sprite(); 
var spr2:Sprite = new Sprite(); 
var spr3:Sprite = new Sprite(); 
 
// objects to use as values 
var groupA:Object = new Object(); 
var groupB:Object = new Object(); 
 
// Create new key-value pairs in dictionary. 
groupMap[spr1] = groupA; 
groupMap[spr2] = groupB; 
groupMap[spr3] = groupB; 
 
if (groupMap[spr1] == groupA) 
{ 
    trace("spr1 is in groupA");  
} 
if (groupMap[spr2] == groupB) 
{ 
    trace("spr2 is in groupB");  
} 
if (groupMap[spr3] == groupB) 
{ 
    trace("spr3 is in groupB");  
}

Wykonywanie iteracji za pomocą kluczy obiektowych

Możliwe jest iterowanie zawartości obiektu Dictionary. Można w tym celu użyć pętli for..in lub pętli for each..in . Pętla for..in pozwala iterować na podstawie kluczy, podczas gdy pętla for each..in umożliwia iterowanie na podstawie wartości skojarzonych z poszczególnymi kluczami.

Należy skorzystać z pętli for..in w celu zażądania dostępu do kluczy obiektowych obiektu Dictionary. Można również uzyskać dostęp do wartości w obiekcie Dictionary za pomocą operatora dostępu do tablicy ( [] ). W poniższym kodzie zastosowano poprzedni przykład słownika groupMap w celu przedstawienia sposobu iterowania w obiekcie Dictionary przy użyciu pętli for..in .

for (var key:Object in groupMap) 
{ 
    trace(key, groupMap[key]); 
} 
/* output: 
[object Sprite] [object Object] 
[object Sprite] [object Object] 
[object Sprite] [object Object] 
*/

Należy skorzystać z pętli for each..in w celu uzyskania bezpośredniego dostępu do wartości w obiekcie Dictionary. W poniższym kodzie zastosowano również słownik groupMap w celu przedstawienia sposobu iterowania w obiekcie Dictionary za pomocą pętli for each..in .

for each (var item:Object in groupMap) 
{ 
    trace(item); 
} 
/* output: 
[object Object] 
[object Object] 
[object Object] 
*/

Klucze obiektowe oraz zarządzanie pamięcią

Programy Adobe® Flash® Player i Adobe® AIR™ korzystają z systemu czyszczenia pamięci w celu uwolnienia pamięci od obiektów, które nie są już używane. Jeśli dla obiektu nie istnieją żadne odniesienia, obiekt taki staje się obiektem podlegającym czyszczeniu pamięci, a pamięć jest uwalniania przy najbliższym wykonaniu czyszczenia. Na przykład poniższy kod umożliwia utworzenie nowego obiektu i przypisanie odniesienia do tego obiektu do zmiennej myObject .

var myObject:Object = new Object();

Tak długo, jak istnieje jakiekolwiek odniesienie do obiektu, system czyszczenia pamięci pomija ten obiektu przy czyszczeniu pamięci. W przypadku modyfikacji zmiennej myObject w taki sposób, aby wskazywała na inny obiekt, lub ustawienia dla niej wartości null , obiekt oryginalny zaczyna podlegać czyszczeniu, lecz tylko wówczas, gdy nie istnieją żadne inne odniesienia prowadzące do obiektu oryginalnego.

W przypadku używania zmiennej myObject w charakterze klucza dla obiektu Dictionary tworzone jest kolejne odniesienie do obiektu oryginalnego. Na przykład poniższy kod powoduje utworzenie dwóch odniesień do obiektów — zmiennej myObject oraz klucza w obiekcie myMap .

import flash.utils.Dictionary; 
 
var myObject:Object = new Object(); 
var myMap:Dictionary = new Dictionary(); 
myMap[myObject] = "foo";

Aby objąć obiekt, do którego odnosi się zmienna myObject , czyszczeniem pamięci, konieczne jest usunięcie wszystkich prowadzących do niego odniesień. W takim przypadku należy zmienić wartość myObject oraz usunąć klucz myObject z obiektu myMap , tak jak w poniższym kodzie.

myObject = null; 
delete myMap[myObject];

Można również użyć parametru useWeakReference konstruktora Dictionary w celu zmiany wszystkich kluczy słownikowych na słabe odniesienia . System czyszczenia pamięci pomija słabe odniesienia, co oznacza, że obiekt, do którego istnieją wyłącznie słabe odniesienia, podlega czyszczeniu. Na przykład poniższy kod nie wymaga usunięcia klucza myObject z obiektu myMap w celu sprawienia, aby obiekt ten podlegał czyszczeniu.

import flash.utils.Dictionary; 
 
var myObject:Object = new Object(); 
var myMap:Dictionary = new Dictionary(true); 
myMap[myObject] = "foo"; 
myObject = null; // Make object eligible for garbage collection.