ios - stored - Crea un Setter solo en Swift
swift didset (8)
Cuando creo un setter como este:
var masterFrame:CGRect{
set{
_imageView.frame = newValue
_scrollView.frame = newValue
}
}
Me obliga a hacer un captador, lo que no quiero hacer.
¿Hay alguna manera de crear un setter en Swift sin un getter?
Bueno, si realmente tengo que hacerlo, usaría esto.
public subscript(index: Int) -> T {
get {
fatalError("You cannot read from this object.")
}
set(v) {
}
}
Esto se verifica en el tiempo de ejecución, pero claramente entregará su intención al usuario del código.
Sería bueno si el compilador Swift soporta algunos atributos en getters.
public subscript(index: Int) -> T {
@availability(*,unavailable)
get {
fatalError("You cannot read from this object.")
}
set(v) {
}
}
Pero esto no funciona actualmente: P (Swift 1.2, Versión 6.3.1 (6D1002))
La forma más rápida y sencilla sería preguntar esto en Apple Radar y Apple Developer Forum.
De la docs :
El captador se utiliza para leer el valor y el definidor se utiliza para escribir el valor. La cláusula de establecimiento es opcional, y cuando solo se necesita un captador, puede omitir ambas cláusulas y simplemente devolver el valor solicitado directamente, como se describe en Propiedades calculadas de solo lectura. Pero si proporciona una cláusula de establecimiento, también debe proporcionar una cláusula de obtención.
He encontrado una excepción en la que realmente me gusta una variable exclusiva del configurador que es cuando paso un cierre como el único parámetro en un método con el único propósito de guardarlo para su posterior ejecución.
Lo implemento como método de la siguiente manera:
typealias ThemeSetter = () -> ()
class Theme {
fileprivate var themeSetters:[ThemeSetter] = []
class var shared: Theme {
struct Singleton {
static let instance = Theme()
}
return Singleton.instance
}
...
func setColor(_ entry:@escaping ThemeSetter) {
entry()
themeSetters.append(entry)
}
}
Entonces puedo llamar al método de la siguiente manera:
Theme.shared.setColor({
self.navigationBar.barTintColor = Theme.shared.gameBarTint
})
Pero no me gustan las paréntesis de cierre después del paréntesis de cierre, ya que puedo tener muchas líneas en el cierre.
Por lo tanto, sabiendo acerca de Trailing Closures puedo cambiar el código para que se vea así:
Theme.shared.setColor() {
self.navigationBar.barTintColor = Theme.shared.gameBarTint
}
Esto está perfectamente bien y es la sintaxis que Apple muestra para Trailing Closures. Ya que solo hay un parámetro y siendo el minimalista que soy, estoy tentado de hacer que el código sea aún más simple y reducirlo a esto:
Theme.shared.setColor {
self.navigationBar.barTintColor = Theme.shared.gameBarTint
}
Que es otra vez cómo Apple muestra hacer Trailing Closures; Excepto, esta forma se usa generalmente para algún tipo de Predicado donde el cierre se usa para indicar al método cómo hacer una clasificación o cuando el cierre se usa al final de una llamada de función asíncrona como un cierre completo. Lo que quiero es asignar el cierre a ... Algo.
Si sustituyo el método para setColor con una variable, se verá así:
var setColor:ThemeSetter? {
didSet {
if setColor != nil {
setColor?()
themeSetters.append(setColor!)
setColor = nil
}
}
}
Ahora la llamada se ve así:
Theme.shared.setColor = {
self.navigationBar.barTintColor = Theme.shared.gameBarTint
}
Ese signo igual significa que toda la diferencia es. Muestra que estoy asignando un cierre y no ejecutando alguna función que usa el cierre, aunque lo haga. : '') <- necesito un emoticon aquí.
Notas finales: Esto realmente no tiene nada que ver con los cierres, solo muestra cómo se puede hacer una variable de solo establecimiento, excepto que todavía devuelve un cero. No pretende proteger a la clase de que el usuario acceda a la variable para leerla como lo haría un verdadero establecedor. Además, perdona el tutorial sobre Trailing Closures y Singletons.
Puede que no obtenga suficientes votos para ser la respuesta correcta, pero ¿por qué es la respuesta correcta, "No, no puedes! ¡Debes usar un método de llamada!". Digo, "Ni" a eso, quien necesita toda esa sintaxis. Solo use una variable y no la lea de nuevo o si lo hace, no haga que devuelva nada. Algo así como la respuesta de Rudolf Adamkovic, que obtuvo 0 Up Votes.
Para tener una "propiedad solo de establecedor", solo puede tener una función simple que establezca el valor; por ejemplo, si tenemos una propiedad privada llamada value
, podemos tener un método de establecimiento llamado, configureWithValue(value:String)
que actualiza la propiedad pero no permite el acceso externo a la propiedad:
private var value:String
func configureWithValue(value:String) {
self.value = value
}
Por supuesto. Solo puedes devolver un nulo y hacer que el tipo sea opcional:
var color: MyColorEnum? {
get { return nil }
set {
switch newValue! {
case .Blue:
view.backgroundColor = UIColor.blueColor()
case .Red:
view.backgroundColor = UIColor.redColor()
}
}
}
Alternativamente, puede usar didSet
para evitar el problema por completo:
var color: MyColorEnum! {
didSet {
switch color {
case .Blue:
view.backgroundColor = UIColor.blueColor()
case .Red:
view.backgroundColor = UIColor.redColor()
}
}
}
Puedes devolver nil
desde get
:
var input: CGRect? {
set(value) {
guard let value = value else { return }
// process the value here
}
get {
return nil
}
}
Una propiedad de conjunto único no suena como que tiene mucho sentido. Probablemente deberías usar un método para eso.
O simplemente haz que el compilador sea feliz y agrega un receptor que nunca llamas:
get {
return _imageView.frame
}
Use didSet en su lugar:
var masterFrame:CGRect {
didSet {
_imageView.frame = masterFrame
_scrollView.frame = masterFrame
}
}