简体   繁体   English

如何在没有在 Swift 中使用引用类型的情况下将 @escaping 用于在 didSet 中使用的函数?

[英]How can use @escaping for a func which used in didSet without using a reference type in Swift?

This down code works just fine!这个向下的代码工作得很好! As soon as I update testFunc, with '@escaping', it start make error about一旦我用'@escaping'更新testFunc,它就会开始出错

Escaping closure captures mutating 'self' parameter转义闭包捕获变异的“自我”参数

struct TestType {

    var string: String {
        didSet(oldValue) {
            if (oldValue != string) {
  
                testFunc(string: string, result: { resultValue in
                    value = resultValue
                })
            }
        }
    }
    
   private(set) var value: String
 
}


func testFunc(string: String, result: (String) -> Void) {
    result(string + " updated!")
}

my goal is to be able use:我的目标是能够使用:

func testFunc(string: String, result: @escaping (String) -> Void) {
    result(string + " updated!")
}

How can I solve the issue without using a reference type?如何在不使用引用类型的情况下解决问题?

The problem with capturing mutating self in an @escaping closure in a struct is there are really only two choices in how Swift might theoretically attempt to do it.struct中的@escaping闭包中捕获变异self的问题在于,理论上 Swift 可能会尝试如何做到这一点实际上只有两种选择。

The first is to capture a reference to the struct , but in many cases it lives on the stack.第一个是捕获对struct的引用,但在许多情况下它存在于堆栈中。 Since the @escaping closure could be called later, that means writing to the position on the stack where self was , but likely isn't there anymore.由于可以稍后调用@escaping闭包,这意味着写入堆栈上self所在的位置,但可能不再存在。 If that happens when the stack has shrunk, then you're writing to an address that is effectively unreachable by any other code.如果在堆栈缩小时发生这种情况,那么您正在写入一个任何其他代码实际上都无法访问的地址。 If it happens when the stack has grown back (or larger), then you're likely stomping on unrelated data, possibly some function's return address.如果它发生在堆栈重新增长(或更大)时,那么您可能会踩到不相关的数据,可能是某个函数的返回地址。 If you're lucky the result will be that the program crashes.如果幸运的话,结果将是程序崩溃。 If you're unlucky, it will silently do the wrong thing.如果你不走运,它会默默地做错事。

Another possible implementation is that Swift could capture a copy, which of course, could be safely written to, but would be inaccessible to any other code.另一种可能的实现是 Swift 可以捕获一个副本,当然,可以安全地写入该副本,但任何其他代码都无法访问。 That's pretty pointless.这很没有意义。

There is a third option Swift could do, which is it could box the struct (that is actually place it on the heap). Swift 还有第三种选择,它可以将结构装箱(实际上就是将它放在堆上)。 The problem is that nothing else would know about the heap location.问题是没有其他人会知道堆位置。 Again that's pretty pointless... and much much slower than allocating things on the stack.同样,这毫无意义……而且比在堆栈上分配东西要慢得多。

If you really need to capture a mutating self , then you need TestType to be a class , but that means the rest of your code has to be written with reference semantics in mind.如果你真的需要捕获一个变异的self ,那么你需要TestType是一个class ,但这意味着你的其余代码必须在编写时考虑到引用语义。

Very likely, you need to think about whatever problem you're trying to solve in a different way.很有可能,您需要考虑以不同的方式尝试解决的任何问题。 Without knowing what that is, concrete solutions are impossible to suggest.如果不知道那是什么,就不可能提出具体的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM