标签: property-wrapper

期望 SwiftUI DynamicProperty 属性包装器的内部更新触发视图更新是否正确?

我正在尝试创建 SwiftUI 支持的自定义属性包装器,这意味着对相应属性值的更改会导致 SwiftUI 视图的更新。这是我所拥有的简化版本:

@propertyWrapper
public struct Foo: DynamicProperty {
    @ObservedObject var observed: SomeObservedObject

    public var wrappedValue: [SomeValue] {
        return observed.value
    }
}
Run Code Online (Sandbox Code Playgroud)

我看到即使 myObservedObject包含在我的自定义属性包装器中,SwiftUI 仍然会捕获更改,SomeObservedObject只要:

  • 我的属性包装器是一个结构
  • 我的财产包装符合 DynamicProperty

不幸的是,文档很少,我很难判断这是否仅适用于当前的 SwiftUI 实现。

DynamicProperty(在 Xcode 中,而不是在线)的文档似乎表明这样的属性是从外部更改导致视图重绘的属性,但是无法保证当您使自己的类型符合此协议时会发生什么。

我可以期待这在未来的 SwiftUI 版本中继续工作吗?

swift swiftui property-wrapper

16
推荐指数
1
解决办法
1569
查看次数

SwiftUI:ObservableObject 不会在重绘时保持其状态

问题

为了实现应用程序代码的简洁外观,我为每个包含逻辑的视图创建了 ViewModel。

一个普通的 ViewModel 看起来有点像这样:

class SomeViewModel: ObservableObject {

    @Published var state = 1

    // Logic and calls of Business Logic goes here
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用:

struct SomeView: View {

    @ObservedObject var viewModel = SomeViewModel()

    var body: some View {
        // Code to read and write the State goes here
    }
}
Run Code Online (Sandbox Code Playgroud)

当视图父级未更新时,这可以正常工作。如果父级的状态发生变化,这个视图会被重绘(在声明性框架中很正常)。但是ViewModel 也会被重新创建,并且之后不会保存状态。与其他框架(例如:Flutter)相比,这是不寻常的。

在我看来,ViewModel 应该保留,或者 State 应该保留。

如果我用一个@State属性替换 ViewModel并int直接使用(在本例中)它会保持持久化并且不会重新创建

struct SomeView: View {

    @State var state = 1

    var body: some …
Run Code Online (Sandbox Code Playgroud)

declarative swift swiftui property-wrapper

16
推荐指数
2
解决办法
3131
查看次数

Access name of object being wrapped, in Swift property wrapper implementation

I'm using Swift property wrappers to define something like:

@MyWrapper var foo: Int
Run Code Online (Sandbox Code Playgroud)

And in the implementation of the property wrapper, I'd like to access the name of the variable, foo, as a string. Something like this:

@propertyWrapper
public struct MyWrapper<Type> {
  init() {
    // Get access to "foo" -- name of var as String
  }
}
Run Code Online (Sandbox Code Playgroud)

Suggestions?

swift property-wrapper

13
推荐指数
1
解决办法
880
查看次数

Swift 中 @Binding 和 Binding&lt;Type&gt; 之间的区别

我知道这@Binding是一个属性包装器,我相信这Binding<Type>是一种类型转换的形式,但实际上有什么区别?

例如声明一个 var,如下所示:

@Binding
var hidden: Bool
Run Code Online (Sandbox Code Playgroud)

相对

var hidden: Binding<Bool>
Run Code Online (Sandbox Code Playgroud)

swift swiftui property-wrapper

12
推荐指数
1
解决办法
2388
查看次数

如何编写 swift 属性包装器?

我最近一直在试验 swift 属性包装器,想知道是否有任何方法可以将它们组合在一起以实现更加模块化的架构。例如:

@WrapperOne @WrapperTwo var foo: T
Run Code Online (Sandbox Code Playgroud)

查看文档一无所获。关于如何做到这一点的唯一参考是在这个 GitHub 页面(https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md)(下面的引用),这似乎在说有可能的。其他文章说他们很难撰写,但没有解释如何去做。但是,我无法理解它,如果有人可以向我展示一些关于如何实现它的示例代码(见帖子底部),我将不胜感激。

当为给定属性提供多个属性包装器时,包装器组合在一起以获得两种效果。例如,考虑的组合物DelayedMutableCopying

@DelayedMutable @Copying var path: UIBezierPath
Run Code Online (Sandbox Code Playgroud)

在这里,我们有一个可以延迟初始化的属性。当我们确实设置了一个值时,它将通过NSCopying的 copy 方法进行复制。组合是通过将较晚的包装类型嵌套在较早的包装类型中来实现的,其中最内层的嵌套类型是原始属性的类型。对于上面的示例,后备存储将是类型 DelayedMutable<Copying<UIBezierPath>> ,路径的合成 getter/setter 将查看 .wrappedValue 的两个级别:

private var _path: DelayedMutable<Copying<UIBezierPath>> = .init()
var path: UIBezierPath {
    get { return _path.wrappedValue.wrappedValue }
    set { _path.wrappedValue.wrappedValue = newValue }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这种设计意味着属性包装器组合不是可交换的,因为属性的顺序会影响嵌套的执行方式:@DelayedMutable @Copying var path1: UIBezierPath // _path1 has type DelayedMutable> @Copying @DelayedMutable var path2: UIBezierPath / / 错误:_path2 有格式错误的类型 Copying> 在这种情况下,类型检查器会阻止第二次排序,因为DelayedMutable不符合NSCopying …

swift property-wrapper

11
推荐指数
1
解决办法
1983
查看次数

将自定义属性包装器与@Published相结合

我希望将自定义属性包装器应用于已包装在 中的变量@Published,将它们像
(A) @Custom @Published var myVar
(B) @Published @Custom var myVar
一样嵌套 (注意包装器的应用顺序)。

在(A)的情况下,我收到错误

'wrappedValue' is unavailable: @Published is only available on properties of classes

对于(B)

error: key path value type 'Int' cannot be converted to contextual type 'Updating<Int>'

两者都不是特别有帮助。有什么想法如何让它发挥作用吗?

最小代码示例

import Combine

class A {
    @Updating @Published var b: Int
    
    init(b: Int) {
        self.b = b
    }
}

@propertyWrapper struct Updating<T> {
    var wrappedValue: T {
        didSet {
            print("Update: \(wrappedValue)")
        }
    }
} …
Run Code Online (Sandbox Code Playgroud)

swift combine property-wrapper

8
推荐指数
1
解决办法
2809
查看次数

原子属性包装器仅在声明为类时才有效,而不是结构体

我在 Swift 中创建了一个“锁”,并为我的 Swift 类创建了一个使用该锁的 Atomic 属性包装器,因为 Swift 缺少 ObjC 的atomic属性属性。

当我在启用线程清理器的情况下运行我的测试时,它总是捕获使用我的 Atomic 属性包装器的属性上的数据竞争。

唯一有效的是将属性包装器的声明更改为一个类而不是一个结构体,这里的主要问题是:为什么它有效!

print在属性包装器中添加了s 并添加了 lockinit来跟踪创建的对象数量,它与 struct/class 相同,尝试在另一个项目中重现该问题,但也没有用。但是我会添加与问题类似的文件,并让我知道它为什么起作用的任何猜测

public class SwiftLock {

    init() { }

   public func sync<R>(execute: () throws -> R) rethrows -> R {
    objc_sync_enter(self)
    defer { objc_sync_exit(self) }
    return try execute()
    }
}
Run Code Online (Sandbox Code Playgroud)

原子属性包装器

@propertyWrapper struct Atomic<Value> {
    let lock: SwiftLock
    var value: Value

    init(wrappedValue: Value, lock: SwiftLock=SwiftLock()) {
        self.value = wrappedValue
        self.lock = …
Run Code Online (Sandbox Code Playgroud)

ios swift ios-multithreading swift-structs property-wrapper

8
推荐指数
1
解决办法
280
查看次数

有没有办法访问封闭实例“ObservableObject”以从属性包装器中的任何位置调用“objectWillChange.send()”

我正在尝试制作一个类似于 的属性包装器CombinePublished满足我的项目需求),但能够通过向发布者发送存储在 中的值来修改包装的属性projectedValue,如下所示:

// in class
@PublishedMutable var foo = "foo"

$foo.send("bar")
// ...
Run Code Online (Sandbox Code Playgroud)

这是属性包装器的代码:

@propertyWrapper
struct PublishedMutable<Value> {
    static subscript<T: ObservableObject>(
        _enclosingInstance instance: T,
        wrapped wrappedKeyPath: ReferenceWritableKeyPath<T, Value>,
        storage storageKeyPath: ReferenceWritableKeyPath<T, Self>
    ) -> Value {
        get {
            instance[keyPath: storageKeyPath].storage
        }
        set {
            let publisher = instance.objectWillChange
            // This assumption is definitely not safe to make in
            // production code, but it's fine for this demo purpose:
            (publisher as? ObservableObjectPublisher)?.send()
            
            instance[keyPath: storageKeyPath].storage = …
Run Code Online (Sandbox Code Playgroud)

swift combine property-wrapper property-wrapper-published swift-property-wrapper

7
推荐指数
1
解决办法
828
查看次数

Property Wrapper @Lazy 变量线程安全吗?

我们现在有了一种创建惰性变量的新方法。它在swift-evolution/proposals/0258-property-wrappers.md 中有描述:

@propertyWrapper
enum Lazy<Value> {
    case uninitialized(() -> Value)
    case initialized(Value)

    init(wrappedValue: @autoclosure @escaping () -> Value) {
        self = .uninitialized(wrappedValue)
    }

    var wrappedValue: Value {
        mutating get {
            switch self {
            case .uninitialized(let initializer):
                let value = initializer()
                self = .initialized(value)
                return value
            case .initialized(let value):
                return value
            }
        }
        set {
            self = .initialized(newValue)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它是线程安全的实现吗?如果没有,如何重现非线程安全行为?

generics lazy-evaluation lazy-initialization swift property-wrapper

6
推荐指数
1
解决办法
1428
查看次数

如何在主线程中接收@Published var

我将模型作为已发布的变量保留在 ViewModel 中,并从视图中观察它。

\n

当模型进程进入后台线程时,如果您发布模型值,Xcode 线程检查器将会做出反应。

\n
\n

不允许从后台线程发布更改;确保在模型更新时从主线程发布值 \xe2\x80\x8b\xe2\x80\x8b (通过像 receive (on :) 这样的运算符)。

\n
\n

已发出。

\n
@StateObject var viewModel = ViewModel()\n
Run Code Online (Sandbox Code Playgroud)\n
class ViewModel: ObservableObject {\n\n    @Published var model = Model()\n    var thisValue:String {\n        return model.thisValue // I want to use this value in view\n    }\n
Run Code Online (Sandbox Code Playgroud)\n
struct Model {\n    var thisValue:String = "value" // I want to change this value on background threads.\n
Run Code Online (Sandbox Code Playgroud)\n

我想知道如何在主线程中接收模型值,但是\n我不太明白并提出了一个问题。

\n

如果你能告诉我,我会很高兴。

\n

ios swift swiftui combine property-wrapper

6
推荐指数
1
解决办法
2016
查看次数