Вы правильно перечислили все доступные опции. Там нет никакого дополнительного трюка, о котором вы не знаете, если это то, что вы просите. Это просто недостаток Swift, когда (как это часто бывает) вы хотите использовать вспомогательную структуру.
Я постоянно сталкиваюсь с этой проблемой в своем собственном коде. Например:
final class ViewController: UIViewController {
lazy var state = Mover(owner:self)
Это не то, что я действительно хотел сказать, по той же причине, что и вы. Mover должен быть изменчивым и являться структурой. Так что в теории другой Mover мог бы быть назначен на мой state
поверх этого. Мне просто нужно заключить с самим собой договор, чтобы не делать этого, что, увы, не так легко осуществить.
Если все, что вы действительно хотите сделать, это предотвратить замену счетчика с другим интервалом, вы можете использовать наблюдатель didSet
(хотя, конечно, принудительное выполнение выполняется во время выполнения, а не во время компиляции):
var counter = Counter() {
didSet {
if oldValue.interval != counter.interval {
fatalError("hey")
}
}
}
Но вы можете себе представить, что это может быть очень сложно. Каждая мутация заменяет другой счетчик, поэтому меры предосторожности, чтобы убедиться, что эта замена является «просто» результатом мутации, могут быть довольно сложными. Также, если вы собираетесь использовать этот подход, вы, вероятно, захотите навязать самой Counter работу по выяснению того, что является «легальной» мутацией. В этом простом случае мы могли бы использовать равенство:
class Foo {
var counter = Counter() {
didSet {
if oldValue != counter {
fatalError("hey")
}
}
}
init() { }
}
struct Counter : Equatable {
static func ==(lhs:Counter,rhs:Counter) -> Bool {
return rhs.interval == lhs.interval
}
// the rest as before....
}