2015-12-16 18 views
5

Utworzono prostą strukturę o nazwie ShoppingList.Zmiana właściwości obiektu wewnątrz pętli w Swift

struct ShoppingList { 

    var shoppingListId :NSNumber 
    var title :String 
    var groceryItems :[GroceryItem] 

    init() { 
     self.title = "" 
     self.groceryItems = [GroceryItem]() 
     self.shoppingListId = NSNumber(integer: 0) 
    } 

} 

Następny stworzyłem ShoppingList tablicę takiego:

var shoppingLists = [ShoppingList]() 

Potem pobrać listy zakupów itp Teraz iterację shoppingLists i zmienić tytuł, ale to nigdy nie aktualizuje właściwość tytuł .

for var shoppingList in shoppingLists { 
    let items = getGroceryItemsByShoppingList(shoppingList) 
    shoppingList.groceryItems = getGroceryItemsByShoppingList(shoppingList) 
    shoppingList.title = "BLAH" // copied by value 
    print("ShoppingList \(shoppingList.title) has \(shoppingList.groceryItems.count) items") // THIS PRINT BLAH 
} 

print("shoppingLists[0].groceryItems.count \(shoppingLists[0].groceryItems.count)") // THIS PRINTS THE ORIGINAL CONTENT 

Wierzę, że gdy uruchamiam pętlę, kopiuje ona według wartości i dlatego oryginalna tablica nigdy się nie zmienia. Jak mogę zmienić oryginalną tablicę za pomocą pętli For?

+0

Dziękuję za zamieszczenie jasnego i zwięzłego pytania, odnowiłeś moją wiarę w programistów. – RyanR

Odpowiedz

7

Są dwa podejścia, których użyłbym tutaj. Pierwsze podejście polega na ponownym rozważeniu, czy ShoppingList jest typem wartości lub typem odniesienia. Fakt, że ma on identyfikator sugeruje mi, że jest to naprawdę typ referencyjny. Jeśli dwie listy zakupów mają tę samą zawartość, czy należy uznać tę samą listę za taką samą? Podejrzewam, że nie. Co to znaczy mieć dwie listy, które mają ten sam identyfikator, ale inną treść? Jeśli to jest nielegalne, to znowu wskazuje, że jest to typ odniesienia, ponieważ ma tożsamość.

Jeśli jest to rodzaj odniesienia, sprawiają, że final class:

final class ShoppingList {} 

Klasy końcowe zachować prostotę elemencie, ponieważ nie cierpią problemy dziedziczenia. Ale zapewniają one semantykę odniesienia. Po tej zmianie Twój oryginalny kod zadziała.

Inny sposób podejścia do tego jest bardziej funkcjonalny, gdzie wszystko jest wartością. W tym przypadku można to osiągnąć poprzez mapowanie kopie list zakupów:

shoppingLists = shoppingLists.map { list in 
    var newList = list 
    newList.groceryItems = getGroceryItemsByShoppingList(list) 
    return newList 
} 

To popycha nas w kierunku podejścia bardziej funkcjonalne, ale to sprawia, że ​​identyfikator niezręczne. Więc jeśli naprawdę chcesz iść w ten sposób, chciałbym pozbyć się identyfikatorów, a może nawet uczynić niezliczoną listę zakupów. W takim przypadku dowolne dwie identyczne listy zakupów są tą samą listą i możesz pisać w bardziej funkcjonalnym stylu.

Ale podejrzewam, że uczynienie z ShoppingList typu referencyjnego jest lepszym podejściem.

+0

Bardzo podoba mi się twój argument na temat typów wartości vs ref. Ponieważ lista zakupów ma identyfikator (shoppingListId), lepiej jest mieć go jako typ ref., Jak sugerujesz. –

1

W porządku, wymyśliłem to. Wydaje się, że sposób, w jaki teraz to robisz, polega na tworzeniu odniesienia i zmianie jego właściwości wewnątrz pętli (co nie zmienia oryginalnej instancji w przypadku struktur). Zamiast tego zadzwoń do nich bezpośrednio:

for index in 0..<shoppingLists.count { 

//Stuff you do. Do the same way, just replace "shoppingList" to "shoppingLists[index]" 

shoppingLists[index].title = "BLAH" // copied by value 
    print("ShoppingList \(shoppingLists[index].title) has items") // THIS PRINT BLAH 

} 

print("shoppingLists[0].groceryItems.title: \(shoppingLists[0].title)") // Returns "shoppingLists[0].groceryItems.title: BLAH" 

To działa, sprawdziłem, nie ma za co!

+0

Jeśli pominiesz "var", to traktujesz instancję jako "niech", co znaczy "stała" i nie możesz zmienić stałej. –

+0

Jednak wciąż możesz zmienić jego właściwości, man – EBDOKUM

+0

Nie, jeśli jest to struktura! –

Powiązane problemy