Lazy Var vs Let


Quiero usar la inicialización perezosa para algunas de mis propiedades en Swift. Mi código actual se ve así:

lazy var fontSize : CGFloat = {
  if (someCase) {
    return CGFloat(30)
  } else {
    return CGFloat(17)
  }
}()

La cosa es que una vez que se establece el tamaño de fuente, nunca cambiará. Así que quería hacer algo como esto:

lazy let fontSize : CGFloat = {
  if (someCase) {
    return CGFloat(30)
  } else {
    return CGFloat(17)
  }
}()

Que es imposible.

Solo esto funciona:

let fontSize : CGFloat = {
  if (someCase) {
    return CGFloat(30)
  } else {
    return CGFloat(17)
  }
}()

Así que - Quiero una propiedad que se cargará perezosamente pero nunca cambiará. ¿Cuál es la forma correcta de hacerlo? usando let y olvidarse de la perezosa init? O debería usar lazy var y olvídese de la naturaleza constante de la propiedad?

Author: Bill, 2015-01-11

3 answers

Esta es la escritura más reciente de Xcode 6.3 Beta / Swift 1.2 notas de la versión :

Que las constantes se han generalizado para que ya no requieran inicialización. La nueva regla es que una constante let debe ser inicializado antes de su uso (como un var), y que solo puede ser inicializado: no reasignado ni mutado después de la inicialización.

Esto habilita patrones como:

let x: SomeThing
if condition {
    x = foo()
} else {
    x = bar()
}

use(x)

Que anteriormente requería el uso de un var, incluso aunque no hay mutación en curso. (16181314)

Evidentemente no eras la única persona frustrada por esto.

 22
Author: Chris Conover,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-11 00:46:05

Swift book tiene la siguiente nota :

Siempre debe declarar una propiedad lazy como variable (con la palabra clave var), porque su valor inicial podría no recuperarse hasta después de que se complete la inicialización de la instancia. Las propiedades constantes siempre deben tener un valor antes de que se complete la inicialización, y por lo tanto no se pueden declarar como perezosas.

Esto tiene sentido en el contexto de la implementación del lenguaje, porque todas las propiedades almacenadas constantes son se calcula antes de que finalice la inicialización de un objeto. Esto no significa que la semántica de let podría haber sido cambiada cuando se usa junto con lazy, pero no se ha hecho, por lo que var sigue siendo la única opción con lazy en este punto.

En cuanto a las dos opciones que usted presentó van, yo decidiría entre ellos basado en la eficiencia:

  • Si el acceso al valor de una propiedad se hace rara vez, y es costoso de calcular por adelantado, yo usaría var lazy
  • Si se accede al valor en más de 20..30% de los casos o es relativamente barato de calcular, usaría let

Nota: Optimizaría aún más su código para insertar el condicional en CGFloat inicializador:

let fontSize : CGFloat = CGFloat(someCase  ? 30 : 17)
 19
Author: dasblinkenlight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-11 10:37:21

Como dasblinkenlight señala, las propiedades perezosas siempre deben declararse como variables en Swift. Sin embargo, es posible hacer que la propiedad sea de solo lectura para que solo pueda mutarse desde el archivo fuente en el que se definió la Entidad. Esto es lo más cerca que puedo llegar a definir un "perezoso".

private(set) lazy var fontSize: CGFloat = {
    if someCase {
        return 30
    } else {
        return 17
    }
}()
 7
Author: sdduursma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-16 23:04:54