programowanieiOS developer

Wyjaśnij różnice między value types a reference types w Swift. Kiedy należy używać każdego z nich?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

W Swift istnieją dwa podstawowe typy danych: value types (typy wartości) i reference types (typy referencyjne).

  • Value types. Należą do nich struktury (struct), wyliczenia (enum) oraz typy podstawowe, takie jak Int, Double, Bool. Przy przekazywaniu lub przypisywaniu wartość jest kopiowana, co oznacza, że zmiany w kopii nie wpływają na oryginał.
  • Reference types. To klasy (class) i pokrewne typy. Przy przekazywaniu nie kopiowany jest sam obiekt, lecz odniesienie do niego, więc zmiany poprzez jeden wskaźnik są widoczne także przez inne.

Kiedy używać:

  • Używaj value types, jeśli chcesz, aby dane były niezależnymi kopiami (np. CGPoint, CGSize, modele, które nie powinny dzielić stanu).
  • Reference types są odpowiednie, gdy wymagane jest dzielenie stanu między obiektami (np. menedżery, kontrolery, usługi).

Przykład:

struct Point { var x: Int var y: Int } class Person { var name: String init(name: String) { self.name = name } } var p1 = Point(x: 0, y: 0) var p2 = p1 p2.x = 10 // p1.x pozostaje 0 var person1 = Person(name: "Alex") var person2 = person1 person2.name = "Sam" // person1.name również staje się "Sam"

Pytanie z pułapką.

Czym różni się let dla struct i class? Czy instancja class, stworzona za pomocą let, jest całkowicie niezmiennicza?

Odpowiedź:

Dla value types (struct) let czyni obiekt i jego właściwości niezmiennymi.

Dla reference types (class) let zakazuje ponownego przypisywania odniesienia, ale nie chroni właściwości obiektu. Można je zmieniać, jeśli nie są zadeklarowane jako let wewnątrz klasy.

Przykład:

class Box { var value: Int init(value: Int) { self.value = value } } let box = Box(value: 10) box.value = 20 // OK! // box = Box(value: 30) // Błąd: nie można ponownie przypisać box

Przykłady rzeczywistych błędów spowodowanych brakiem wiedzy na temat tego tematu.


Historia

W aplikacji płatniczej model transakcji był definiowany jako klasa, mimo że stanu być nie powinno. Powstał błąd: podczas jednoczesnej pracy z listą transakcji dochodziło do nieprzewidywalnej edycji danych różnych części interfejsu. Postanowiono przekształcić modele w struct, aby każdy komponent pracował z własną kopią.


Historia

W projekcie przechowywano ustawienia użytkownika w klasie, sądząc, że wartości są kopiowane przy przekazywaniu. Podczas zmiany danych jeden ekran przypadkowo wpływał na inny, ponieważ oba pracowały z tym samym odniesieniem do obiektu.


Historia

W module serializacji dane modelu były zadeklarowane jako reference type, co prowadziło do uszkodzenia stanu w pamięci podręcznej przy każdej zmianie. Po wymianie na value types problem zniknął: dane stały się niezależne przy każdej operacji.