2016-08-31 78 views
8

Przeprowadzałem badania na temat powodów, dla których powinniśmy używać Get i Set dla naszych właściwości.Getters and Setters w Swift - Czy zamiast tego warto używać WillSet i DidSet?

Zauważyłem 3 główne powody, dla których to

  1. Kiedy chcesz zrobić/coś sprawdzić zanim faktycznie ustawić właściwość
  2. Kiedy chcesz mieć właściwości, które można uzyskać tylko od to (może dla celów bezpieczeństwa, jak sądzę?), lub dać mu różne poziomy dostępu .
  3. Ukrywanie wewnętrznej reprezentacji właściwości podczas prezentowania właściwości przy użyciu alternatywnej reprezentacji. (Co dla mnie nie uczynić wiele sensu, ponieważ nie mogę do niego dostęp na niewłaściwym miejscu, używając funkcję Set Anyways)

Poniższy kod jest przykładem tego, jak można zaimplementować get i set dla właściwości w Swift, korzystając z tych 3 punktach wspominałem:

class Test 
{ 
    private var _testSet:String! 
    private var _testGetOnly:String 
    var testSet:String{ 
     get{ 
      return _testSet 
     } 
     set{ 
      _testSet = newValue + "you forgot this string" 
     } 
    } 
    var testGetOnly:String!{ 
     get{ 
      return _testGetOnly 
     } 
    } 

    init(testSet:String, testGetOnly:String) 
    { 
     _testSet = testSet 
     _testGetOnly = testGetOnly 
    } 
} 

ale ten drugi przykład poniżej również skorzystać z tych wymienionych punktów, ale zamiast używać inną nieruchomość komputerowej powrót prywatny wartość nieruchomości po prostu używać willSet i didSet obserwatorzy

class Test 
{ 
    var testGet:String { 
     willSet{ 
      fatalError("Operation not allowed") 
     } 
    } 
    var testWillSet:String!{ 
     didSet{ 
      self.testWillSet = self.testWillSet + "you forgot this string" 
     } 
    } 
    init(testGet:String, testWillSet:String) 
    { 
     self.testGet = testGet 
     self.testWillSet = testWillSet 
    } 
} 

Więc jestem ciekawy, jakie są ZALETY i WADY KAŻDEGO wykonania.

góry dzięki

+0

Bardzo interesujące pytanie, ale nie mogę ci pomóc, odkąd tłum został odkryty. .. –

+0

willSet i didSet są ** obserwatorami **. Są całkowicie różne od podmiotów pobierających/ustawiających. (Nawet nie wspominając, że często właściwości w Swift (takie jak w rozszerzeniu protokołu) nie są nawet właściwościami, są obliczonymi właściwościami.) W odpowiedzi na twoje pytanie, tak, z całą pewnością dwaj obserwatorzy są tak wspaniałymi cechami językowymi , że bardzo często zwykłe ** nie musisz się martwić ** o używanie żmudnego wzoru własności/gettera/settera - świetnie. – Fattie

Odpowiedz

3

Twoje pytanie sprowadza się do kompilacji vs. błędu czasu pracy. Aby rozwiązać swoje 3 pytania:

  1. Tak, willCheck jest to jedyna opcja tutaj
  2. właściwości tylko odczyt spadnie na 2 rodzaje: (a) te, których wartości wynikają z innych właściwości, na przykład, ich suma; oraz (b) te, które chcesz samodzielnie zmienić, ale nie przez użytkowników. Pierwszy typ naprawdę nie ma setera; drugi typ ma publiczny getter i prywatny ustawiający. Kompilator może pomóc ci to sprawdzić, a program się nie skompiluje. Jeśli rzucisz fatalError w didSet, pojawi się błąd środowiska wykonawczego, a aplikacja ulegnie awarii.
  3. Mogą istnieć obiekty stanu, w których użytkownik nie chce swobodnie mieszać, i tak, można całkowicie ukryć je przed użytkownikami.

Twój pierwszy przykład kodu był zbyt szczegółowy w definiowaniu zmiennych pomocniczych - nie musisz tego robić. Aby zilustrować te punkty:

class Test 
{ 
    // 1. Validate the new value 
    var mustBeginWithA: String = "A word" { 
     willSet { 
      if !newValue.hasPrefix("A") { 
       fatalError("This property must begin with the letter A") 
      } 
     } 
    } 

    // 2. A readonly property 
    var x: Int = 1 
    var y: Int = 2 
    var total: Int { 
     get { return x + y } 
    } 

    private(set) var greeting: String = "Hello world" 
    func changeGreeting() { 
     self.greeting = "Goodbye world" // Even for private property, you may still 
             // want to set it, just not allowing the user 
             // to do so 
    } 

    // 3. Hide implementation detail 
    private var person = ["firstName": "", "lastName": ""] 
    var firstName: String { 
     get { return person["firstName"]! } 
     set { person["firstName"] = newValue } 
    } 

    var lastName: String { 
     get { return person["lastName"]! } 
     set { person["lastName"] = newValue } 
    } 

    var fullName: String { 
     get { return self.firstName + " " + self.lastName } 
     set { 
      let components = newValue.componentsSeparatedByString(" ") 
      self.firstName = components[0] 
      self.lastName = components[1] 
     } 
    } 
} 

Zastosowanie:

let t = Test() 
t.mustBeginWithA = "Bee"  // runtime error 

t.total = 30     // Won't compile 

t.greeting = "Goodbye world" // Won't compile. The compiler does the check for you 
           // instead of a crash at run time 

t.changeGreeting()    // OK, greeting now changed to "Goodbye world" 

t.firstName = "John"   // Users have no idea that they are actually changing 
t.lastName = "Smith"   // a key in the dictionary and there's no way for them 
           // to access that dictionary 

t.fullName = "Bart Simpsons" // You do not want the user to change the full name 
           // without making a corresponding change in the 
           // firstName and lastName. With a custome setter, you 
           // can update both firstName and lastName to maintain 
           // consistency 

Wzmiankę o private w Swift 2 vs Swift 3: jeśli spróbujesz to w Swift 2 zabaw znajdziesz t.greeting = "Goodbye world" prace w porządku. Dzieje się tak dlatego, że Swift 2 ma dziwny specyfikator poziomu dostępu: private oznacza "dostępny tylko w bieżącym pliku".Oddziel definicję klasy i przykładowy kod na różne pliki, a Xcode będzie narzekać. W Swift 3 zmieniono to na fileprivate, które jest bardziej przejrzyste i zapisuje słowo kluczowe private dla czegoś bardziej zbliżonego do Javy i .NET