ios 是否可以允许在 Swift 初始化期间调用 didSet?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25230780/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to allow didSet to be called during initialization in Swift?
提问by Logan
Question
题
Apple's docsspecify that:
Apple 的文档规定:
willSet and didSet observers are not called when a property is first initialized. They are only called when the property's value is set outside of an initialization context.
willSet 和 didSet 观察者在属性第一次初始化时不会被调用。只有当属性的值设置在初始化上下文之外时才会调用它们。
Is it possible to force these to be called during initialization?
是否可以在初始化期间强制调用这些?
Why?
为什么?
Let's say I have this class
假设我有这门课
class SomeClass {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
init(someProperty: AnyObject) {
self.someProperty = someProperty
doStuff()
}
func doStuff() {
// do stuff now that someProperty is set
}
}
I created the method doStuff
, to make the processing calls more concise, but I'd rather just process the property within the didSet
function. Is there a way to force this to call during initialization?
我创建了方法doStuff
,使处理调用更加简洁,但我宁愿只处理didSet
函数内的属性。有没有办法在初始化期间强制调用它?
Update
更新
I decided to just remove the convenience intializer for my class and force you to set the property after initialization. This allows me to know didSet
will always be called. I haven't decided if this is better overall, but it suits my situation well.
我决定只删除我的类的便利初始化器,并强制您在初始化后设置属性。这让我知道didSet
总会被调用。我还没有决定这是否总体上更好,但它很适合我的情况。
采纳答案by Oliver
Create an own set-Method and use it within your init-Method:
创建一个自己的 set-Method 并在您的 init-Method 中使用它:
class SomeClass {
var someProperty: AnyObject! {
didSet {
//do some Stuff
}
}
init(someProperty: AnyObject) {
setSomeProperty(someProperty)
}
func setSomeProperty(newValue:AnyObject) {
self.someProperty = newValue
}
}
By declaring
someProperty
as type:AnyObject!
(an implicitly unwrapped optional), you allow self to fully initialize withoutsomeProperty
being set. When you callsetSomeProperty(someProperty)
you're calling an equivalent ofself.setSomeProperty(someProperty)
. Normally you wouldn't be able to do this because self hasn't been fully initialized. SincesomeProperty
doesn't require initialization and you are calling a method dependent on self, Swift leaves the initialization context and didSet will run.
通过声明
someProperty
为 type:(AnyObject!
一个隐式解包的可选),你允许 self 完全初始化而不someProperty
被设置。当您致电时,setSomeProperty(someProperty)
您正在致电相当于self.setSomeProperty(someProperty)
. 通常你不能这样做,因为 self 还没有完全初始化。由于someProperty
不需要初始化并且您正在调用依赖于 self 的方法,因此 Swift 离开初始化上下文并且 didSet 将运行。
回答by Brian Westphal
If you use defer
inside of an initializer, for updating any optional properties or further updating non-optional properties that you've already initialized and after you've called any super.init()
methods, then your willSet
, didSet
, etc. will be called. I find this to be more convenient than implementing separate methods that you have to keep track of calling in the right places.
如果您使用defer
的内部初始化,更新任何可选属性或进一步更新不可选的属性,你已经初始化,之后你调用的任何super.init()
方法,那么你的willSet
,didSet
等会被调用。我发现这比实现单独的方法更方便,您必须在正确的位置跟踪调用。
For example:
例如:
public class MyNewType: NSObject {
public var myRequiredField:Int
public var myOptionalField:Float? {
willSet {
if let newValue = newValue {
print("I'm going to change to \(newValue)")
}
}
didSet {
if let myOptionalField = self.myOptionalField {
print("Now I'm \(myOptionalField)")
}
}
}
override public init() {
self.myRequiredField = 1
super.init()
// Non-defered
self.myOptionalField = 6.28
// Defered
defer {
self.myOptionalField = 3.14
}
}
}
Will yield:
将产生:
I'm going to change to 3.14
Now I'm 3.14
回答by original_username
As a variation of Oliver's answer, you could wrap the lines in a closure. Eg:
作为 Oliver 答案的一种变体,您可以将这些行包裹在一个闭包中。例如:
class Classy {
var foo: Int! { didSet { doStuff() } }
init( foo: Int ) {
// closure invokes didSet
({ self.foo = foo })()
}
}
Edit: Brian Westphal's answer is nicer imho. The nice thing about his is that it hints at the intent.
编辑:Brian Westphal 的回答更好,恕我直言。他的好处在于它暗示了意图。
回答by Carmine Cuofano
I had the same problem and this works for me
我有同样的问题,这对我有用
class SomeClass {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
init(someProperty: AnyObject) {
defer { self.someProperty = someProperty }
}
func doStuff() {
// do stuff now that someProperty is set
}
}
回答by onmyway133
This works if you do this in a subclass
如果您在子类中执行此操作,则此方法有效
class Base {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
required init() {
someProperty = "hello"
}
func doStuff() {
print(someProperty)
}
}
class SomeClass: Base {
required init() {
super.init()
someProperty = "hello"
}
}
let a = Base()
let b = SomeClass()
In a
example, didSet
is not triggered. But in b
example, didSet
is triggered, because it is in the subclass. It has to do something with what initialization context
really means, in this case the superclass
did care about that
在a
例子中,didSet
不会被触发。但是在b
example 中,didSet
是触发的,因为它在子类中。它必须做一些initialization context
真正意味着什么,在这种情况下,superclass
确实关心那个
回答by C?ur
In the particular case where you want to invoke willSet
or didSet
inside init
for a property available in your superclass, you can simply assign your super property directly:
在您想要为超类中可用的属性调用willSet
或didSet
inside的特定情况下init
,您可以简单地直接分配您的超属性:
override init(frame: CGRect) {
super.init(frame: frame)
// this will call `willSet` and `didSet`
someProperty = super.someProperty
}
Note that Charlesismsolution with a closure would always work too in that case. So my solution is just an alternative.
请注意,在这种情况下,带有闭包的Charlesism解决方案也始终有效。所以我的解决方案只是一个替代方案。
回答by Snowman
While this isn't a solution, an alternative way of going about it would be using a class constructor:
虽然这不是解决方案,但另一种解决方法是使用类构造函数:
class SomeClass {
var someProperty: AnyObject {
didSet {
// do stuff
}
}
class func createInstance(someProperty: AnyObject) -> SomeClass {
let instance = SomeClass()
instance.someProperty = someProperty
return instance
}
}
回答by yshilov
You can solve it in obj-с way:
你可以用obj-с的方式解决它:
class SomeClass {
private var _someProperty: AnyObject!
var someProperty: AnyObject{
get{
return _someProperty
}
set{
_someProperty = newValue
doStuff()
}
}
init(someProperty: AnyObject) {
self.someProperty = someProperty
doStuff()
}
func doStuff() {
// do stuff now that someProperty is set
}
}