Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
`@发布的变量名称:ClassType“不工作”\u在SwiftUI/手动触发器之外?_Swift_Key Value Observing_Combine_Reference Type - Fatal编程技术网

`@发布的变量名称:ClassType“不工作”\u在SwiftUI/手动触发器之外?

`@发布的变量名称:ClassType“不工作”\u在SwiftUI/手动触发器之外?,swift,key-value-observing,combine,reference-type,Swift,Key Value Observing,Combine,Reference Type,我发现了很多与SwiftUI相关的话题,但都没有帮助 这不适用于Swift中的联合收割机,特别是不使用SwiftUI: 类任务{ @已发布的var progress=ProgresstotalUnitCount:5//progress是一个类 [...] } var task=SomeTask let cancelable=task.$progress.sink{print$0.fractionCompleted} task.progress.completedUnitCount=2 这与Swi

我发现了很多与SwiftUI相关的话题,但都没有帮助

这不适用于Swift中的联合收割机,特别是不使用SwiftUI:

类任务{ @已发布的var progress=ProgresstotalUnitCount:5//progress是一个类 [...] } var task=SomeTask let cancelable=task.$progress.sink{print$0.fractionCompleted} task.progress.completedUnitCount=2 这与SwiftUI无关,因此没有ObserveObject继承来获取objectWillChange,但即使我尝试使用ObserveObject和task.objectWillChange.send,它也不会做任何事情,同时尝试添加扩展进度:ObserveObject{}也没有帮助。 由于发布者通过var的willSet发出值,并且由于Progress本身就是类类型,所以不会发生任何事情

看起来没有真正像样的方法手动触发它

我找到的唯一解决办法是重新分配自己,这相当尴尬:

让pr=进步 进度=pr

写入进度=进度是一个编译时错误

唯一可行的方法可能是使用键值/KVO和/或编写新的@PublishedClassType属性包装?

您可以尝试使用CurrentValueSubject:

这样,您的进度仍然可以是一个类。

您可以尝试使用CurrentValueSubject:


这样,您的进度仍然可以是一个类。

我能够使用KVO实现这一点,KVO由@PropertyRapper包装,CurrentValueSubject作为发布者:

@propertyWrapper
class PublishedClass<T : NSObject> {
    private let subject: CurrentValueSubject<T, Never>
    private var observation: NSKeyValueObservation? = nil

    init<U>(wrappedValue: T, keyPath: ReferenceWritableKeyPath<T, U>) {
        self.wrappedValue = wrappedValue
        subject = CurrentValueSubject(wrappedValue)
        observation = wrappedValue.observe(keyPath, options: [.new]) { (wrapped, change) in
            self.subject.send(wrapped)
        }
    }

    var wrappedValue: T

    var projectedValue: CurrentValueSubject<T, Never> {
        subject
    }

    deinit {
        observation.invalidate()
    }
}
输出:

0
2
3
4
当然,使用KVO的缺点是,传入的密钥路径必须是@objc dynamic,并且密钥路径的根必须是NSObject子类:


我还没有尝试过,但如果您愿意,应该可以扩展它以在多个关键路径上观察。

我能够使用KVO实现这一点,KVO由@PropertyRapper包装,CurrentValueSubject作为发布者:

@propertyWrapper
class PublishedClass<T : NSObject> {
    private let subject: CurrentValueSubject<T, Never>
    private var observation: NSKeyValueObservation? = nil

    init<U>(wrappedValue: T, keyPath: ReferenceWritableKeyPath<T, U>) {
        self.wrappedValue = wrappedValue
        subject = CurrentValueSubject(wrappedValue)
        observation = wrappedValue.observe(keyPath, options: [.new]) { (wrapped, change) in
            self.subject.send(wrapped)
        }
    }

    var wrappedValue: T

    var projectedValue: CurrentValueSubject<T, Never> {
        subject
    }

    deinit {
        observation.invalidate()
    }
}
输出:

0
2
3
4
当然,使用KVO的缺点是,传入的密钥路径必须是@objc dynamic,并且密钥路径的根必须是NSObject子类:


我还没有尝试过,但是如果你愿意的话,应该可以扩展它以观察多个关键路径。

基于我的想法,我实现了@PublishedKVO属性包装器,并将其作为一个小型swift包放在github上,支持多个关键路径

可用作:

课例{ @PublishedKVO\.completedUnitCount var progress=ProgresstotalUnitCount:2 @出版 var textualRepresentation=text } 让我们举个例子 //设立出版商 设c1=ex.$progress.sink{print\$0.fractionCompleted} 设c1=ex.$textualRepresentation.sink{print\$0} //像往常一样与班级互动 ex.progress.completedUnitCount+=1 //完成产出0.5 //并与几乎相同的行为相比较 ex.textualRepresentation=字符串 //输出字符串 例如$progress.emit//重新发出当前值 例如$progress.sendex.progress//发出给定值
基于这些想法,我实现了@PublishedKVO属性包装器,并将其作为一个小型swift包放在github上,支持多个关键路径

可用作:

课例{ @PublishedKVO\.completedUnitCount var progress=ProgresstotalUnitCount:2 @出版 var textualRepresentation=text } 让我们举个例子 //设立出版商 设c1=ex.$progress.sink{print\$0.fractionCompleted} 设c1=ex.$textualRepresentation.sink{print\$0} //像往常一样与班级互动 ex.progress.completedUnitCount+=1 //完成产出0.5 //并与几乎相同的行为相比较 ex.textualRepresentation=字符串 //输出字符串 例如$progress.emit//重新发出当前值 例如$progress.sendex.progress//发出给定值
如果Progress是一个类,那么@Published var Progress是对Progress实例的引用,当您更改该实例的属性时,引用本身不会更改,因此var Progress不会更改,因此即使您正确设置了其他所有内容,也不会发布任何内容。是的,这就是我在最初的问题中所说的。请仔细阅读,如果难以理解,请道歉。那么,你知道如何使这项工作的答案吗?看起来没有直接的方法触发它,类似于物体的变化。最简单的是结构的进步。谢谢,它实际上是一个基础类型,所以…是的,我可以创建自己的结构进度,这是最简单的方法。写一个新的@PropertyRapper PublishedClassTypes并找到一种方法怎么样?如果你只限于标准进度,例如与其他系统API集成时使用它,那么我会在某个任务中使用KVO,比如Progress.completedUnitCount和report self.objectWillChange.send in KVO回调。如果进度是一个类,那么@Published var Progress是对Progress实例的引用,当您更改该实例的属性时

ce,引用本身没有改变,所以var progress没有改变,所以即使您正确设置了其他所有内容,也没有什么要发布的。是的,这就是我在最初的问题中所说的。请仔细阅读,如果难以理解,请道歉。那么,你知道如何使这项工作的答案吗?看起来没有直接的方法触发它,类似于物体的变化。最简单的是结构的进步。谢谢,它实际上是一个基础类型,所以…是的,我可以创建自己的结构进度,这是最简单的方法。写一个新的@PropertyRapper PublishedClassTypes并找到一种方法怎么样?如果你只局限于标准进度,例如与其他系统API集成时使用它,那么我会在某个任务中使用KVO,比如Progress.completedUnitCount和report self.objectWillChange.send in KVO回调。谢谢你,这是一个小而手动的方法!我正在考虑一种更通用的方法,目前正在修补KVO和带有KeyPath的定制@PropertyRapper。此外,我认为还有一个小错误:setProgress可能应该更改completedUnitCount,而不是TotalUnitCount谢谢。如果你找到了一个解决方案,请将其作为答案发布。@pawello2222我想我找到了一个解决方案。是的,看来我自己的聚会迟到了,但我也将这些想法落实到了@PublishedKVO属性包装中。我用它做了一个小的swift软件包。你的解决方案看起来很有趣,我会研究它们的,谢谢。谢谢你,一个小但手动的方法!我正在考虑一种更通用的方法,目前正在修补KVO和带有KeyPath的定制@PropertyRapper。此外,我认为还有一个小错误:setProgress可能应该更改completedUnitCount,而不是TotalUnitCount谢谢。如果你找到了一个解决方案,请将其作为答案发布。@pawello2222我想我找到了一个解决方案。是的,看来我自己的聚会迟到了,但我也将这些想法落实到了@PublishedKVO属性包装中。我用它做了一个小的swift包。你的解决方案看起来很有趣,我会研究它们的,谢谢。当我准备自己的@PublishedKVO时,你比我快了几分钟;我没有运行您的代码,但这是示例原则。只是想知道既然我们不写,为什么选择ReferenceWritableKeyPath,对吗?这可能只是普通的键路径。@smat88dd从技术上讲,是的,我们可以使用键路径,但将具有值语义的可写键路径传递给它有意义吗?这个属性包装器不是为类设计的吗?如果密钥路径是只读的,订阅它是否仍然有用?它将只发布1个值?我选择ReferenceWritableKeyPath是因为在这里接受任何其他内容都可能是错误的。也许我忽略了传递其他类型的键路径的有用性?是的,属性包装器是为类设计的,但这一事实与键路径的类型完全无关。我们仅对KVO使用密钥路径,以说明我们感兴趣阅读的内容。我们从不使用键路径来写入底层属性。另外,我不明白为什么关键路径与我们发布的值有任何关系,这也是完全无关的。我使用的是KeyPath,工作完美,顺便说一句@smat88dd请参阅。清理将自动进行。我使用ReferenceWritableKeyPath是因为订阅例如只读属性实际上没有多大意义,而且很可能是一个打字错误。这与Swift不允许progress=progress的精神是一样的,因为将一个变量赋给它本身很可能是一个输入错误。@smat88dd我并不是说它对KeyPath不起作用。我从来没说过。我试图做的是不允许像@PublishedClasskeyPath:\.a这样的事情,其中a是一个let常量,就像你不能用Published from Combine做@Published let a=1一样。为什么我不允许这样做?因为let常量不能发布任何有用的内容。如果@PublishedClasskeyPath:\.aLetConstant曾出现在您的代码中,则可能是输入错误。这也是为什么Swift不允许progress=progress的原因——这可能是一个打字错误。但是,我想,这是一个意见问题。当我准备自己的@PublishedKVO时,你比我快了几分钟;我没有运行您的代码,但这是示例原则。只是想知道既然我们不写,为什么选择ReferenceWritableKeyPath,对吗?这可能只是普通的键路径。@smat88dd从技术上讲,是的,我们可以使用键路径,但将具有值语义的可写键路径传递给它有意义吗?这个属性包装器不是为类设计的吗?如果密钥路径是只读的,订阅它是否仍然有用?它将只发布1个值?我选择ReferenceWritableKeyPath是因为在这里接受任何其他内容都可能是错误的。也许我忽略了传递其他类型的键路径的有用性?是的,属性包装器是为类设计的,但这一事实与键路径的类型完全无关。我们仅对KVO使用密钥路径,以说明我们感兴趣阅读的内容。我们从不使用键路径来写入底层属性。还有,我不明白
为什么keypath与我们发布多少值有关,这也是完全无关的。我使用的是KeyPath,工作完美,顺便说一句@smat88dd请参阅。清理将自动进行。我使用ReferenceWritableKeyPath是因为订阅例如只读属性实际上没有多大意义,而且很可能是一个打字错误。这与Swift不允许progress=progress的精神是一样的,因为将一个变量赋给它本身很可能是一个输入错误。@smat88dd我并不是说它对KeyPath不起作用。我从来没说过。我试图做的是不允许像@PublishedClasskeyPath:\.a这样的事情,其中a是一个let常量,就像你不能用Published from Combine做@Published let a=1一样。为什么我不允许这样做?因为let常量不能发布任何有用的内容。如果@PublishedClasskeyPath:\.aLetConstant曾出现在您的代码中,则可能是输入错误。这也是为什么Swift不允许progress=progress的原因——这可能是一个打字错误。不过,我想这是个意见问题。
0
2
3
4