[英]How to call a method once two variables have been set
I am using iOS Swift, and I am trying to understand how to execute a method
once the value of two variables have been set up (non-null value) once the requests have finished.我正在使用 iOS Swift,并且我试图了解在请求完成后设置两个变量的值(非空值)后如何执行
method
。
After reading some documentation, I have found out some concepts which are interesting.在阅读了一些文档之后,我发现了一些有趣的概念。 The first one would be
didSet
, which works as an observer
.第一个是
didSet
,它作为observer
工作。
I could call the method using this method by simply using didSet
if I would require just one variable如果我只需要一个变量,我可以通过简单地使用
didSet
来调用该方法
didSet设置
var myVar: String 0 {
didSet {
print("Hello World.")
}
}
Nevertheless, I also need to wait for the second one myVar2
, so it would not work.不过,我还需要等待第二个
myVar2
,所以它不起作用。
I have also found DispatchQueue
, which I could use to wait a second before calling the method (the requests that I am using are pretty fast)我还找到了
DispatchQueue
,我可以在调用该方法之前使用它等待一秒钟(我正在使用的请求非常快)
DispatchQueue调度队列
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
print("Hello world")
})
but I consider that this solution is not efficient.但我认为这个解决方案效率不高。
Is there anyway to combine these two variables or requests in order to call a method once they have finishing setting the value?无论如何将这两个变量或请求组合起来,以便在完成设置值后调用方法?
Update I have tried to replicate David s answer, which I believe is correct but I get the following error on each \.
更新我试图复制大卫的答案,我认为这是正确的,但我在每个
\.
Type of expression is ambiguous without more context
在没有更多上下文的情况下,表达式的类型是模棱两可的
I copy here my current code我在这里复制我当前的代码
var propertiesSet: [KeyPath<SearchViewController, Car>:Bool] = [\SearchViewController.firstCar:false, \SearchViewController.secondCar:false] {
didSet {
if propertiesSet.allSatisfy({ $0.value }) {
// Conditions passed, execute your custom logic
print("All Set")
} else {
print("Not yet")
}
}
}
var firstCar: Car? {
didSet {
propertiesSet[\SearchViewController.firstCar] = true
}
}
var secondCar: Car? {
didSet {
propertiesSet[\SearchViewController.secondCar] = true
}
}
The variables are set individually, each one on its own request.变量是单独设置的,每个变量都是根据自己的要求设置的。
You could make your properties optional
and check they both have values set before calling your function
.您可以将属性设为
optional
,并在调用function
之前检查它们是否都设置了值。
var varA: String? = nil {
didSet {
if varA != nil && varB != nil {
myFunc()
}
}
}
var varB: String? = nil {
didSet {
if varA != nil && varB != nil {
myFunc()
}
}
}
Or you can call your function
on each didSet
and use a guard
condition at the start of your function
to check that both of your properties have values, or bail out:或者,您可以在每个
didSet
上调用function
并在function
的开头使用guard
条件来检查您的两个属性是否都有值,或者退出:
var varA: String? = nil {
didSet {
myFunc()
}
}
var varB: String? = nil {
didSet {
myFunc()
}
}
func myFunc() {
guard varA != nil && varB != nil else { return }
// your code
}
First, you should think very carefully about what your semantics are here.首先,您应该非常仔细地考虑您的语义在这里。 When you say "set," do you mean "assigned a value" or do you mean "assigned a non-nil value?"
当您说“设置”时,您的意思是“分配了一个值”还是“分配了一个非零值”? (I assume you mean the latter in this case.) You should ask yourself, what should happen if your method has already fired, and then another value is set?
(在这种情况下,我假设您的意思是后者。)您应该问自己,如果您的方法已经触发,然后设置了另一个值,会发生什么? What if one of the properties has a value is set, then nil is set, then another value set?
如果其中一个属性设置了一个值,然后设置了 nil,然后设置了另一个值,该怎么办? Should that fire the method 1, 2, or 3 times?
那应该触发该方法 1、2 或 3 次吗?
Whenever possible you should work to make these kinds of issues impossible by requiring that the values be set together, in an init
rather than mutable properties, for example.只要有可能,您应该通过要求将值设置在一起(例如在
init
而不是可变属性中)来努力使这类问题变得不可能。
But obviously there are cases where this is necessary (UI is the most common).但显然在某些情况下这是必要的(UI 是最常见的)。
If you're targeting iOS 13+, you should explore Combine for these kinds of problems.如果您的目标是 iOS 13+,您应该探索结合这些类型的问题。 As one approach:
作为一种方法:
class Model: ObservableObject {
@Published var first: String?
@Published var second: String?
@Published var ready = false
private var observers: Set<AnyCancellable> = []
init() {
$first.combineLatest($second)
.map { $0 != nil && $1 != nil }
.assign(to: \.ready, on: self)
.store(in: &observers)
}
}
let model = Model()
var observers: Set<AnyCancellable> = []
model.$ready
.sink { if $0 { print("GO!") } }
.store(in: &observers)
model.first = "ready"
model.second = "set"
// prints "GO!"
Another approach is to separate the incidental state that includes optionals, from the actual object you're constructing, which does not.另一种方法是将附带的包含选项的 state 与您正在构建的实际 object 分开,但事实并非如此。
// Possible parameters for Thing
struct Parameters {
var first: String?
var second: String?
}
// The thing you're actually constructing that requires all the parameters
struct Thing {
let first: String
let second: String
init?(parameters: Parameters) {
guard let first = parameters.first,
let second = parameters.second
else { return nil }
self.first = first
self.second = second
}
}
class TheUIElement {
// Any time the parameters change, try to make a Thing
var parameters: Parameters = Parameters() {
didSet {
thing = Thing(parameters: parameters)
}
}
// If you can make a Thing, then Go!
var thing: Thing? {
didSet {
if thing != nil { print("GO!") }
}
}
}
let element = TheUIElement()
element.parameters.first = "x"
element.parameters.second = "y"
// Prints "GO!"
You need to add a didSet
to all variables that need to be set for your condition to pass.您需要为所有需要设置的变量添加一个
didSet
以使您的条件通过。 Also create a Dictionary
containing KeyPath
s to your variables that need to be set and a Bool
representing whether they have been set already.还要创建一个
Dictionary
,其中包含需要设置的变量的KeyPath
和一个表示它们是否已经设置的Bool
。
Then you can create a didSet
on your Dictionary
containing the "set-state" of your required variables and when all of their values are true
meaning that all of them have been set, execute your code.然后,您可以在
Dictionary
上创建一个didSet
,其中包含所需变量的“设置状态”,当它们的所有值都为true
时,意味着所有这些值都已设置,执行您的代码。
This solution scales well to any number of properties due to the use of a Dictionary
rather than manually writing conditions like if aSet && bSet && cSet
, which can get out of hand very easily.由于使用
Dictionary
而不是手动编写条件,例如if aSet && bSet && cSet
,该解决方案可以很好地扩展到任意数量的属性,这很容易失控。
class AllSet {
var propertiesSet: [KeyPath<AllSet, String>:Bool] = [\.myVar:false, \.myVar2:false] {
didSet {
if propertiesSet.allSatisfy({ $0.value }) {
// Conditions passed, execute your custom logic
print("All Set")
} else {
print("Not yet")
}
}
}
var myVar: String {
didSet {
propertiesSet[\.myVar] = true
}
}
var myVar2: String {
didSet {
propertiesSet[\.myVar2] = true
}
}
init(myVar: String, myVar2: String) {
self.myVar = myVar
self.myVar2 = myVar2
}
}
let all = AllSet(myVar: "1", myVar2: "2")
all.myVar = "2" // prints "Not yet"
all.myVar2 = "1" // prints "All set"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.