简体   繁体   English

设置两个变量后如何调用方法

[英]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.

相关问题 仅在设置了数据后如何调用完成处理程序? - How do I call the completion handler only once the data has been set? 只有在我的 UIView 子类中设置了所有属性后,如何才能调用函数? - How can I call a function only after all properties have been set in my UIView subclass? 一旦删除项目后如何重新填充数组 - how to repopulate an array once items have been removed swift indexsOfObjectsPassingTest:| 找到索引后,如何检查它们是否为顺序索引? - indexesOfObjectsPassingTest: | once indexes have been found how to check if if they are sequential? 完成块完成后如何调用方法? - How to call a method once the completion block finish? 调用某些方法后如何添加方法 - How to add a method after certain methods have been called 如何更新以前在代码中设置的NSLayoutConstraint常量? -迅捷 - How to update NSLayoutConstraint constants, that have previously been set in code? - Swift 弹出 iOS UINavigationController 时如何调用方法? - How to call a method when an iOS UINavigationController has been popped? 一旦另一个类通过CA Transition设置了Xamarin iOS中的视图控制器上的隐藏属性 - How to set a hidden property on a view controller in Xamarin iOS once it has been set by another class with a CA Transition 如何限制我的对象在iOS中只能调用一次方法? - How to restrict my objects to call a method only once in iOS?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM