Геттеры и сеттеры в Swift - имеет ли смысл использовать WillSet и DidSet вместо этого?
Я делал некоторые исследования о причинах мы должны использовать GET и Set для свойства.
Я заметил 3 основные причины для этого
- когда вы хотите сделать / проверить что-то, прежде чем фактически установить собственность
- когда вы хотите иметь свойство, которое вы можете получить только от него (может быть, в целях безопасности, я думаю? ), или дать ему другой доступ уровни.
- скрытие внутреннего представления свойства при выставлении ля свойство с использованием альтернативного представления. (что для меня не сделать много смысла, так как я могу получить доступ к нему в неправильном месте, используя функция Set в любом случае)
приведенный ниже код является примером того, как вы реализуете Get и Set для свойств в Swift, используя те 3 пункта, которые я упомянул:
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
}
}
но этот другой пример ниже также использует упомянутые точки, но вместо использования другого вычисляемого свойства для возврата значение частной собственности я просто использую наблюдателей willSet и 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
}
}
поэтому мне любопытно узнать, каковы преимущества и недостатки каждой реализации.
спасибо заранее
1 ответов
Ваш вопрос сводится к компиляции и ошибок времени выполнения. Чтобы ответить на ваши 3 вопроса:
- да
willCheck
- это ваш единственный вариант здесь - только для чтения свойства делятся на 2 типа: (a) те, значение которых происходит от других свойств, например, их суммы; и (b) те, которые вы хотите иметь возможность изменять самостоятельно, но не пользователями. Первый тип действительно не имеет сеттера; второй тип имеет публичный геттер и частная сеттер. Компилятор может помочь вам проверить это, и программа не будет компилироваться. Если вы бросаете
fatalError
наdidSet
вы получите ошибку времени выполнения, и ваше приложение рухнет. - могут быть объекты состояния, с которыми вы не хотите, чтобы пользователь свободно возился, и да, вы можете полностью скрыть их от пользователей.
ваш первый пример кода был слишком подробным в определении резервных переменных - вам не нужно этого делать. Для иллюстрации этих очки:
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]
}
}
}
использование:
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
Примечание private
в Swift 2 против Swift 3: если вы попробуете это на игровой площадке Swift 2, вы найдете t.greeting = "Goodbye world"
работает просто отлично. Это потому, что Swift 2 имеет странный спецификатор уровня доступа:private
означает "доступно только в текущем файле". Разделите определение класса и пример кода на разные файлы, и Xcode будет жаловаться. В Swift 3 это было изменено на fileprivate
что и яснее и сохранить private
ключевое слово для чего-то более похожего на Java и .NET