Можно ли добавить наблюдателя на переменную структуры в Swift? - PullRequest
0 голосов
/ 17 января 2019

Мне нужно отслеживать обновление в переменной типа структуры. Можно ли добавить наблюдателя на переменную структуры в Swift?

Пример:

struct MyCustomStruct {
    var error:Error?
    var someVar:String?
}

class MyClass{
  var myCustomStruct:MyCustomStruct?
}

Я хочу добавить наблюдателя в переменную myCustomStruct.

Ответы [ 4 ]

0 голосов
/ 18 января 2019

Стандартные Swift « наблюдатели свойств » (didSet и willSet) предназначены для того, чтобы тип мог наблюдать изменения своих собственных свойств, но не для того, чтобы внешние объекты могли добавлять своих собственных наблюдателей. А KVO, который поддерживает внешние наблюдатели, предназначен только для dynamic и @objc свойств NSObject подклассов (как описано в Использование наблюдения значения ключа в Swift ).

Итак, если вы хотите, чтобы внешний объект наблюдал изменения в пределах struct, как указывали другие, вы должны создать свой собственный механизм наблюдателя, используя Swift didSet и т.п. Но вместо того, чтобы реализовывать это самостоятельно, свойство за свойством, вы можете написать универсальный тип, чтобы сделать это для вас. Например.,

struct Observable<T> {
    typealias Observer = String

    private var handlers: [Observer: (T) -> Void] = [:]

    var value: T {
        didSet {
            handlers.forEach { $0.value(value) }
        }
    }

    init(_ value: T) {
        self.value = value
    }

    @discardableResult
    mutating func observeNext(_ handler: @escaping (T) -> Void) -> Observer {
        let key = UUID().uuidString as Observer
        handlers[key] = handler
        return key
    }

    mutating func remove(_ key: Observer) {
        handlers.removeValue(forKey: key)
    }
}

Тогда вы можете делать такие вещи, как:

struct Foo {
    var i: Observable<Int>
    var text: Observable<String>

    init(i: Int, text: String) {
        self.i = Observable(i)
        self.text = Observable(text)
    }
}

class MyClass {
    var foo: Foo

    init() {
        foo = Foo(i: 0, text: "foo")
    }
}

let object = MyClass()
object.foo.i.observeNext { [weak self] value in   // the weak reference is really only needed if you reference self, but if you do, make sure to make it weak to avoid strong reference cycle
    print("new value", value)
}

И тогда, когда вы обновите свойство, например, как показано ниже, будет закрыто ваше обработчик наблюдателя:

object.foo.i.value = 42

Стоит отметить, что фреймворки, такие как Bond или RxSwift , предлагают такую ​​функциональность, а также многое другое.

0 голосов
/ 17 января 2019

Попробуйте, сначала создайте структуру с переменной действия, а когда вы создаете объект структуры, задайте параметр действия для требуемого действия.напр.

struct testStruct {
var action: (()->())?
var variable: String? {
    didSet {
        self.action?()
    }
}

}

А внутри вашего основного кода - основной класс

var testS = testStruct()
    testS.action = {
        print("Hello")
    }
    testS.variable = "Hi"

Когда вы установите testS.variabe = "Hi", он вызоветпечать ( "Hello")

0 голосов
/ 17 января 2019
struct MyCustomStruct {
    var error:Error?
    var someVar:String?
}

class MyClass{
    var myCustomStruct:MyCustomStruct? {
        didSet{
            print("my coustomeSruct changed")
        }
    }
}

let aClass = MyClass()
aClass.myCustomStruct?.someVar = " test"
 //prints:my coustomeSruct changed
0 голосов
/ 17 января 2019

С переменными вы можете использовать два наблюдателя по умолчанию

  • willSet - представляет момент до того, как переменная будет установлена ​​с новым значением

  • didSet - представляет момент, когда была установлена ​​переменная


Также в обозревателе вы можете работать с двумя значениями. С текущей переменной в текущем состоянии и с постоянной в зависимости от наблюдателя

struct Struct {
    var variable: String {
        willSet {
            variable  // before set 
            newValue  // after set,  immutable
        }
        didSet {
            oldValue  // before set, immutable
            variable  // after set
        }
    }
}

То же самое вы можете сделать для любого другого хранимого свойства, чтобы вы могли использовать его и для переменных структуры в вашем классе

class Class {
    var myStruct: Struct? {
        didSet {
            ...
        }
    }
}

Также вы можете, например, установить наблюдатель переменной почтового уведомления с определенным именем

didSet {
    NotificationCenter.default.post(name: Notification.Name("VariableSet"), object: nil)
}

и затем вы можете добавить определенный класс в качестве наблюдателя для уведомления с этим именем

class Class {
    init() {
        NotificationCenter.default.addObserver(self, selector: #selector(variableSet), name: Notification.Name("VariableSet"), object: nil)
    }

    deinit {
        NotificationCenter.default.removeObserver(self, name: Notification.Name("VariableSet"), object: nil)
    }

    @objc func variableSet() {
        ...
    }
}
...