2016-08-31 16 views
8

Tôi đã thực hiện một số nghiên cứu về lý do chúng tôi nên sử dụng Nhận và Đặt cho các thuộc tính của chúng tôi.Getters and Setters in Swift - Thay vào đó bạn có sử dụng WillSet và DidSet không?

tôi đã nhận thấy 3 lý do chính cho nó

  1. Khi bạn muốn làm/kiểm tra một cái gì đó trước khi bạn thực sự thiết lập các tài sản
  2. Khi bạn muốn có một tài sản mà bạn chỉ có thể Get from nó (có thể vì mục đích bảo mật tôi đoán?), hoặc cung cấp cho nó truy cập khác nhau cấp độ.
  3. Ẩn đại diện nội bộ của thuộc tính trong khi phơi bày thuộc tính bằng cách sử dụng đại diện thay thế. (Mà đối với tôi không làm cho rất nhiều ý nghĩa kể từ khi tôi có thể truy cập nó trên sai chỗ sử dụng các chức năng Cài đặt anyways)

Đoạn code dưới đây là một ví dụ về cách bạn sẽ thực hiện Get và Set cho tài sản trong Swift, lợi dụng những 3 điểm tôi đã đề cập:

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 
    } 
} 

nhưng ví dụ này khác dưới đây cũng tận dụng những điểm được đề cập nhưng thay vì sử dụng một tài sản tính toán để trả lại giá trị tài sản cá nhân tôi chỉ sử dụng các willSet và người theo dõi didSet

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 
    } 
} 

Vì vậy, tôi rất tò mò muốn biết các ƯU ĐIỂM và DISADVANTAGES của từng triển khai là gì.

Cảm ơn trước

+0

Câu hỏi rất thú vị, nhưng tôi thực sự không thể giúp bạn vì đám đông đã được phát hiện. .. –

+0

willSet và didSet là ** quan sát **. Chúng hoàn toàn khác với getters/setters. (Thậm chí không đề cập rằng các thuộc tính thường trong Swift (chẳng hạn như trong một phần mở rộng giao thức) thậm chí không phải là các thuộc tính, chúng là các thuộc tính được tính toán.) Trong câu trả lời cho câu hỏi của bạn, vâng, bằng mọi cách, hai quan sát là các tính năng ngôn ngữ tuyệt vời , điều đó, rất thường xuyên bạn đồng bằng ** không phải bận tâm ** về việc sử dụng mẫu tài sản/getter/setter tẻ nhạt nữa - tuyệt vời. – Fattie

Trả lời

3

Câu hỏi của bạn sẽ giải thích thời gian so với lỗi thời gian chạy. Để giải quyết 3 câu hỏi của bạn:

  1. Vâng, willCheck là lựa chọn duy nhất của bạn ở đây
  2. thuộc tính chỉ đọc rơi vào 2 loại: (a) những người có giá trị bắt nguồn từ các tài sản khác, ví dụ, số tiền của họ; và (b) những người mà bạn muốn có thể tự thay đổi, nhưng không phải bởi người dùng. Loại đầu tiên thực sự không có setter; loại thứ hai có bộ thu công khai và thiết lập riêng tư. Trình biên dịch có thể giúp bạn kiểm tra điều đó và chương trình sẽ không biên dịch. Nếu bạn ném fatalError vào didSet bạn gặp lỗi thời gian chạy và ứng dụng của bạn sẽ bị lỗi.
  3. Có thể có các đối tượng trạng thái mà bạn không muốn người dùng tự do xáo trộn, và có, bạn hoàn toàn có thể ẩn chúng khỏi người dùng.

Ví dụ đầu tiên về mã của bạn quá chi tiết trong việc xác định biến số sao lưu - bạn không cần thực hiện điều đó. Để minh họa cho những điểm sau:

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] 
     } 
    } 
} 

Cách sử dụng:

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 

Một lưu ý về private trong Swift 2 vs Swift 3: nếu bạn thử điều này trong một sân chơi Swift 2, bạn sẽ tìm thấy t.greeting = "Goodbye world" công trình bình thường. Điều này là do Swift 2 có một trình chỉ định mức truy cập lạ: private có nghĩa là "chỉ có thể truy cập trong tệp hiện tại".Phân tách định nghĩa lớp và mã mẫu thành các tệp khác nhau và Xcode sẽ khiếu nại. Trong Swift 3, được thay đổi thành fileprivate, cả hai đều rõ ràng hơn và lưu từ khóa private cho một cái gì đó giống với Java và .NET

Các vấn đề liên quan