Apple的框架如何使用具有自身静态属性的结构体

问题描述 投票:0回答:1

Apple 使用以下结构来设置

PresentationBackgroundInteraction

public struct PresentationBackgroundInteraction : Sendable {
    public static var automatic: PresentationBackgroundInteraction { get }
    public static func enabled(upThrough detent: PresentationDetent) -> PresentationBackgroundInteraction
    ...
}

然后可以在视图修改器中使用它,如下所示;

    .presentationBackgroundInteraction(.enabled(upThrough(.medium))
  1. 但是这是如何运作的呢?每个调用都会实例化该结构体的一个实例,但是我们如何获取在另一个位置分配的值?我们需要在某个地方引用这个实例。
  2. Apple 如何知道在哪里放置此引用并使用它?
  3. 为什么更喜欢这个而不是枚举?

如果我尝试重新创建 Apple 的设置,我会遇到一些问题。让函数返回本身当然会创建无限递归;

public static func enabled(upThrough detent: PresentationDetent) -> PresentationBackgroundInteraction {
    .enabled(upThrough: detent)
}

将其分配给内部变量当然可以缓解这个问题。

但是,如果我将它用作视图修饰符,它总是返回结构的实例,而不是我分配的值。所以我永远不能根据传递给我的视图修饰符的值进行更改。

结构

public struct PresentationBackgroundInteractionRecreate : Sendable {
    public static var automatic: PresentationBackgroundInteractionRecreate = .automatic
}

查看

EmptyView()
    .presentationBackgroundInteractionRecreate(.automatic)

视图修改器

extension View {
    public func presentationBackgroundInteractionRecreate(
        _ interaction: presentationBackgroundInteractionRecreate
    ) -> some View {
        // This now always returns; PresentationBackgroundInteractionRecreate()
        // How would I be able to access `automatic` here
        print(interaction) 
        return EmptyView()
    }
}
swift struct enums static
1个回答
0
投票

基于使用

Mirror
dump
进行一些基本的逆向工程,我发现
PresentationBackgroundInteraction
基本上是一个枚举的包装器,如下所示:

public struct PresentationBackgroundInteractionRecreate: Hashable, Sendable {
    internal enum Kind: Hashable {
        case automatic
        case disabled
        case enabled(upThrough: PresentationDetent?)
    }
    
    internal let kind: Kind
    
    internal init(kind: Kind) {
        self.kind = kind
    }
    
    public static let automatic = Self.init(kind: .automatic)
    public static let enabled = Self.init(kind: .enabled(upThrough: nil))
    public static let disabled = Self.init(kind: .disabled)
    
    public func enabled(upThrough detent: PresentationDetent) -> Self {
        .init(kind: .enabled(upThrough: detent))
    }
}

据我所知,

internal
部分甚至可能是
fileprivate

视图修改器可以轻松读取

kind
。反映
presentationBackgroundInteraction
返回的视图,它似乎使用
transformPreference
,所以我想象视图修改器看起来像这样:

extension View {
    func presentationBackgroundInteractionRecreate(_ interaction: PresentationBackgroundInteractionRecreate) -> some View {
        transformPreference(PresentationOptionsPreferenceKey.self) { value in
            switch interaction.kind {
                // change "value" in different ways
            }
        }
    }
}

PresentationOptionsPreferenceKey
是另一种
internal
/
fileprivate
类型。我不知道首选项键的
Value
类型是什么,但要点是正确的。


我可以想到使用结构体而不是枚举的一些优点。使用枚举会比结构公开更多的实现细节。 枚举会立即给出它有多少种不同的情况,并且每种情况都是不同的,而对于结构体,

.automatic

不妨在幕后返回

.disabled
,这将是“公平的游戏”。
使用结构还可以防止人们对不同情况进行详尽的

switch

处理。这使得将来添加更多类型的后台交互变得更加容易。另一方面,枚举强烈向开发人员表明这是一组

固定
的值。

© www.soinside.com 2019 - 2024. All rights reserved.