ios - sumar - tipos de datos en swift
Ejecutar un método cuando un valor variable cambia en Swift (5)
En Swift 4 puedes usar Key-Value Observation.
label.observe(/.text, changeHandler: { (label, change) in {
// text has changed
}
Esto es básicamente eso, pero hay una pequeña trampa. ¡"observe" devuelve un objeto NSKeyValueObservation que debe mantener! - cuando esté desasignado, no recibirá más notificaciones. Para evitar eso podemos asignarlo a una propiedad que será retenida.
var observer:NSKeyValueObservation?
// then assign the return value of "observe" to it
observer = label.observe(/.text, changeHandler: { (label, change) in {
// text has changed,
}
También puede observar si el valor ha cambiado o se ha establecido por primera vez.
observer = label.observe(/.text, changeHandler: { (label, change) in {
// just check for the old value in "change" is not Nil
if let oldValue = change.oldValue {
print("/(label.text) has changed from /(oldValue) to /(label.text)")
} else {
print("/(label.text) is now set")
}
}
Para más información, consulte la documentación de Apple here
Necesito ejecutar una función cuando un valor variable cambia.
Tengo una clase de singleton que contiene una variable compartida llamada labelChange
. Los valores de esta variable se toman de otra clase llamada Model
. Tengo dos clases de VC, una de ellas tiene un botón y una etiqueta y la segunda solo un botón.
Cuando se presiona el botón en la primera clase de VC, estoy actualizando la etiqueta con esta función:
func updateLabel(){
self.label.text = SharingManager.sharedInstance.labelChange
}
Pero quiero llamar al mismo método siempre que se cambie el valor de labelChange
. Por lo tanto, al hacer clic en el botón solo actualizaré el valor de labelChange
y, cuando esto suceda, deseo actualizar la etiqueta con el nuevo valor de labelChange
. También en el segundo VC puedo actualizar el valor de labelChange
pero no puedo actualizar la etiqueta cuando se cambia este valor.
Tal vez las propiedades son la solución, pero ¿alguien puede mostrarme cómo hacerlo?
Editado segunda vez:
Clase Singleton:
class SharingManager {
func updateLabel() {
println(labelChange)
ViewController().label.text = SharingManager.sharedInstance.labelChange
}
var labelChange: String = Model().callElements() {
willSet {
updateLabel()
}
}
static let sharedInstance = SharingManager()
}
Primera VC:
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
@IBAction func Button(sender: UIButton) {
SViewController().updateMessageAndDismiss()
}
}
Segundo VC:
func updateMessageAndDismiss() {
SharingManager.sharedInstance.labelChange = modelFromS.callElements()
self.dismissViewControllerAnimated(true, completion: nil)
}
@IBAction func b2(sender: UIButton) {
updateMessageAndDismiss()
}
Hice algunas mejoras pero necesito hacer referencia a una etiqueta de la primera clase de VC en singleton. Por lo tanto voy a actualizar esa etiqueta de VC en singleton.
Cuando labelChange
el valor de labelChange
el valor se está actualizando y todo está bien. Pero cuando intento actualizar ese valor en la etiqueta de singleton recibo un error:
inesperadamente encontrado nil mientras desenvuelve un valor opcional
y el error está apuntando en la cuarta línea de la clase de singleton.
Hay otra forma de hacerlo, utilizando RxSwift:
Agregue los pods RxSwift y RxCocoa a su proyecto
Modifique su
SharingManager
:import RxSwift class SharingManager { static let sharedInstance = SharingManager() private let _labelUpdate = PublishSubject<String>() let onUpdateLabel: Observable<String>? // any object can subscribe to text change using this observable // call this method whenever you need to change text func triggerLabelUpdate(newValue: String) { _labelUpdate.onNext(newValue) } init() { onUpdateLabel = _labelUpdate.shareReplay(1) } }
En su ViewController puede suscribirse a la actualización de valor de dos maneras:
a. Suscríbase a las actualizaciones y cambie el texto de la etiqueta manualmente.
// add this ivar somewhere in ViewController let disposeBag = DisposeBag() // put this somewhere in viewDidLoad SharingManager.sharedInstance.onUpdateLabel? .observeOn(MainScheduler.instance) // make sure we''re on main thread .subscribeNext { [weak self] newValue in // do whatever you need with this string here, like: // self?.myLabel.text = newValue } .addDisposableTo(disposeBag) // for resource management
segundo. enlazar actualizaciones directamente a UILabel
// add this ivar somewhere in ViewController let disposeBag = DisposeBag() // put this somewhere in viewDidLoad SharingManager.sharedInstance.onUpdateLabel? .distinctUntilChanged() // only if value has been changed since previous value .observeOn(MainScheduler.instance) // do in main thread .bindTo(myLabel.rx_text) // will setText: for that label when value changed .addDisposableTo(disposeBag) // for resource management
Y no olvide import RxCocoa
en ViewController.
Para desencadenar el evento solo llame
SharingManager.sharedInstance.triggerLabelUpdate("whatever string here")
HERE puedes encontrar proyectos de ejemplo. Solo haz la pod update
y ejecuta el archivo de espacio de trabajo.
Simplemente puede usar un observador de propiedades para la variable, labelChange
, y llamar a la función que desea llamar dentro de didSet
(o willSet
si desea llamarla antes de que se haya configurado):
class SharingManager {
var labelChange: String = Model().callElements() {
didSet {
updateLabel()
}
}
static let sharedInstance = SharingManager()
}
Esto se explica en los Observadores de la Propiedad .
No estoy seguro de por qué esto no funcionó cuando lo probaste, pero si tienes problemas porque la función que intentas llamar ( updateLabel
) está en una clase diferente, puedes agregar una variable en la clase SharingManager
para almacenar la función a la que se llama cuando se ha llamado a didSet
, que se configuraría para updateLabel
en este caso.
Editado:
Por lo tanto, si desea editar una etiqueta desde ViewController, le gustaría tener esa función updateLabel () en la clase ViewController para actualizar la etiqueta, pero almacenar esa función en la clase singleton para que pueda saber a qué función llamar:
class SharingManager {
static let sharedInstance = SharingManager()
var updateLabel: (() -> Void)?
var labelChange: String = Model().callElements() {
didSet {
updateLabel?()
}
}
}
y luego configúrelo en la clase en la que tenga la función a la que desea llamar, como (asumiendo que updateLabel es la función a la que desea llamar):
SharingManager.sharedInstance.updateLabel = updateLabel
Por supuesto, querrá asegurarse de que el controlador de vista que es responsable de esa función aún exista, para que la clase singleton pueda llamar a la función.
Si necesita llamar a diferentes funciones según el controlador de vista que esté visible, es posible que desee considerar Key-Value Observing para recibir notificaciones cada vez que cambie el valor de ciertas variables.
Además, nunca querrá inicializar un controlador de vista así y luego configurar inmediatamente los IBOutlets del controlador de vista, ya que los IBOutlets no se inicializan hasta que la vista se carga. Necesitas usar un objeto controlador de vista existente de alguna manera.
Espero que esto ayude.
Apple proporciona este tipo de declaración de propiedad: -
1. Propiedades calculadas: -
Además de las propiedades almacenadas, las clases, estructuras y enumeraciones pueden definir propiedades computadas, que en realidad no almacenan un valor. En su lugar, proporcionan un captador y un configurador opcional para recuperar y establecer otras propiedades y valores indirectamente.
var otherBool:Bool = false
public var enable:Bool {
get{
print("i can do editional work when setter set value ")
return self.enable
}
set(newValue){
print("i can do editional work when setter set value ")
self.otherBool = newValue
}
}
2. Propiedades calculadas de solo lectura: -
Una propiedad computada con un captador pero sin definidor se conoce como propiedad computada de solo lectura. Una propiedad calculada de solo lectura siempre devuelve un valor, y se puede acceder a ella mediante la sintaxis de puntos, pero no se puede establecer en un valor diferente.
var volume: Double {
return volume
}
3. Observadores de la propiedad: -
Tiene la opción de definir uno o ambos observadores en una propiedad:
willSet se llama justo antes de que se almacene el valor.
didSet se llama inmediatamente después de que se almacena el nuevo valor.
public var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to /(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added /(totalSteps - oldValue) steps")
}
}
}
NOTA: - Para obtener más información, vaya al enlace profesional https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
var item = "initial value" {
didSet { //called when item changes
print("changed")
}
willSet {
print("about to change")
}
}
item = "p"