Is this a good way of using Enum and static var in enum to manage state in Swift and SwiftUI?

huangapple go评论79阅读模式
英文:

Is this a good way of using Enum and static var in enum to manage state in Swift and SwiftUI?

问题

  1. 定义一个带有两个案例的枚举来替代 true/false 布尔值是一种很好的做法,特别是如果你的代码会更清晰和可读。使用 "selfie" 和 "world" 作为状态名确实更具概念性。

  2. 定义一个 mutating 函数来改变状态也是合理的做法。在 SwiftUI 中,使用 @State 属性包装器时,你可以通过调用这个函数来改变状态,并且 SwiftUI 会自动处理视图的更新。这是一种常见的模式,尤其是当你需要在视图中切换状态时。

  3. 在枚举中定义私有的静态变量也是一个好的做法,特别是当你需要在不同的状态之间共享一些配置时。这可以帮助保持代码的模块化和可维护性。

  4. 从计算属性中调用静态属性也是有效的,特别是在你需要根据当前状态返回不同的配置时。这种做法可以让你的代码更具可读性和可维护性。

总的来说,你的代码看起来很合理,符合良好的 Swift 编程实践。枚举的使用使代码更具表现力,而静态属性和计算属性的结合允许你根据状态返回不同的配置,这是一个很好的设计。继续保持这种良好的实践,它们将有助于代码的可读性和可维护性。

英文:

I am wondering if the following use of Enum, static var, computed property and whatnot are good practices to manage states in Swift and SwiftUI.

I'm learning Swift by myself and don't have anyone to review my code or senior to learn from.

enum ARSessionState {
    case selfie
    case world
    
    mutating func toggle() {
        self = (self == .selfie) ? .world : .selfie
    }
    
    private static var selfieConfiguration: ARFaceTrackingConfiguration = {
        let configuration = ARFaceTrackingConfiguration()
        configuration.isWorldTrackingEnabled = true
        return configuration
    }()
    
    private static var worldConfiguration: ARWorldTrackingConfiguration = {
        let configuration = ARWorldTrackingConfiguration()
        configuration.planeDetection = [.horizontal]
        configuration.userFaceTrackingEnabled = true
        return configuration
    }()

    var configuration: ARConfiguration {
        switch self {
        case .selfie:
            return ARSessionState.selfieConfiguration
        case .world:
            return ARSessionState.worldConfiguration
        }
    }
}

and I use this in a SwiftUI view like this:

struct ContentView : View {
    @State private var session: ARSessionState = .world

    ...
    
    var body: some View {
        
        ZStack {
            
            ...
            
            Button(action: {session.toggle()} ) {

                Image(systemName: "arrow.triangle.2.circlepath.camera")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 50, height: 50)
            
                }.onChange(of: session) { newValue in
                let configuration = session.configuration
                
                ...

            }
        }
    }
}

Rather than using a simple Bool, I wanted to define two states and toggle between them from a Button action because selfie/world made more sense conceptually than true/false. So I defined ARSessionState and added two cases selfie and world.

Now, when the user changes the state, I wanted to have different ARConfigurations to kick-in based on the changed state, namely ARWorldTrackingConfiguration and ARFaceTrackingConfiguration. So inside .onchange {...} I call session.configuration, which should give me corresponding ARConfiguration based on the session's state.

So my questions are, is it a good practice to

  1. define an Enum with two cases like this to replace true/false Bool?

  2. define a mutating func to change the state? I'm not confident how state change will play out in SwiftUI. Specifically with @State property-wrapper.

  3. define private static var properties within Enum? I did this because I could not have stored properties in Enum.

  4. call the static properties from a computed property? (in this case, var configuration: ARConfiguration)

Any other comments related to good Swift programming practices are greatly appreciated too!

答案1

得分: 2

> 定义一个具有两个情况的枚举来替代 true/false 布尔值?

没问题。

> 定义一个可变的函数来改变状态?

我很惊讶它甚至编译通过。鉴于它确实编译通过了,这可能是可以的。个人而言,我更喜欢一个非可变函数,它返回新值。

enum ARSessionState {
    case selfie
    case world
    
    func toggled() -> ARSessionState {
        return (self == .selfie) ? .world : .selfie
    }
}

这样可以提供更多的灵活性,并且在语义上更接近布尔值的 ! 操作符。

> 在枚举内定义私有的静态变量?我这样做是因为在枚举内不能有存储属性。

我完全看不出问题。

> 从计算属性中调用静态属性?(在这种情况下,var configuration: ARConfiguration)

或者那样。

英文:

> define an Enum with two cases like this to replace true/false Bool?

No problem.

> define a mutating func to change the state?

It surprised me to find that it even compiles. Given that it does, it is probably OK. Personally, I'd be happier with a non mutating function that returns the new value

enum ARSessionState {
    case selfie
    case world
    
    func toggled() -> ARSessionState {
        return (self == .selfie) ? .world : .selfie
    }
}

This gives you more flexibility and is closer in semantics to the ! operator for booleans.

> define private static var properties within Enum? I did this because I could not have stored properties in Enum.

I don't see a problem with that at all.

> call the static properties from a computed property? (in this case, var configuration: ARConfiguration)

Or that.

答案2

得分: 1

我自己不是专家(希望有一天能成为),但我想分享我的想法,以便进行信息交流。

将枚举定义为具有两个案例来替代 true/false 布尔值,是否是一种良好的实践?

  • 我认为这是相当合理的。使用具有两个案例(.selfie.world)的枚举提供了更多的清晰度,使您的代码更可读。

mutating func 定义为更改状态的良好实践吗?

  • 我没有理由不使用 mutating func,但为什么呢?我认为更好的方法是使用普通的 func

在枚举内部定义私有的静态变量属性是否是一种良好的实践?

  • 如果您需要封装与枚举相关的某些配置或值,那么为什么不呢?我认为这是合理的。

从计算属性中调用静态属性是否可以接受?

  • 是良好的实践吗?也许。是坏的实践吗?我不这么认为。通过根据枚举的当前状态调用相应的静态属性,您可以方便地提供所需的配置。

总体而言,我觉得您的代码看起来很酷,但如果您需要更多关于如何编写更好的 Swift 代码的提示和方法,我可以建议您阅读这篇文章,我认为它非常不错。有很多关于成为更好的编程人员的文章,您可能已经知道,但万一您不知道,这可能是一个很好的起点。

英文:

I am no expert myself (hopefully one day) but I would like to share my thoughts for the sake of information exchange.

Is it a good practice to define an Enum with two cases like this to replace true/false Bool?

  • I think it's pretty reasonable. Using an enum with two cases (.selfie and .world) provides more clarity and makes your code more readable.

Is it a good practice to define a mutating func to change the state?

  • I don't see a reason not to use a mutating func, but why? I think the better approach is to use a normal func.

Is it a good practice to define private static var properties within an enum?

  • If you need to encapsulate certain configurations or values related to the enum, then why not? I think it's reasonable.

Is it okay to call the static properties from a computed property?

  • Good practice? Maybe. Bad practice? I don't think so. By calling the appropriate static property based on the enum's current state, you can conveniently provide the desired configuration.

Overall your code looks really cool to me, however if you need more tips and ways to write better Swift code, I can suggest you this article which I find really good. There's tons of articles about becoming a better coder and you probably know that but in case you don't, this could be a good starting point.

答案3

得分: 1

你正在征求意见,所以这是我的看法:

  1. 定义一个具有两个情况的枚举,以替代 true/false 的 Bool?

是的,很好。实际上,我认为这是一个好的解决方案,因为如果以后有超过两种情况,你可以将它们添加到枚举中。

  1. 定义一个 mutating 函数来改变状态?

正如其他人评论的那样,我对它能够编译通过感到惊讶。我认为我会选择一个非 mutating 的计算属性,它提供切换后的状态,类似于:

var toggledState: ARSessionState {
    self == selfie ? world : selfie
}
  1. 在枚举内部定义私有的静态变量?

我认为我会将枚举保持为一个不具备其他类知识的低级数据类型。这保持了依赖关系的单向性。在更一般的层面上,我认为为其他低级别类型(例如字符串)定义静态常量(使用 let)没有问题。

  1. 从计算属性调用静态属性?

所以根据第 3 点,我不会在类中包含工厂函数。如果你需要为 ARFaceTrackingConfiguration 创建一个工厂,可以创建一个工厂类。这可能会接受枚举值作为参数。但是,我认为对我来说,似乎可以返回低级数据类型(例如字符串)的简单函数或计算属性是可以的。

英文:

You're asking for opinions so here's my tuppence:
> 1. define an Enum with two cases like this to replace true/false Bool?

Yes fine. In fact, I would say it's a good solution because if you later have more than two cases then you can add them to the enum.

> 2. define a mutating func to change the state?

As someone else commented, I'm surprised it compiles. I think I would go for a non-mutating computed property that delivers the toggled state, something like:

var toggledState: ARSessionState {
    self == selfie ? world : selfie
}

> 3. define private static var properties within Enum?

I think I would keep the enum as a low level data type that does not have knowledge of other classes. This keeps the dependency 1-way. At a more general level, I don't see a problem with defining static constants (using let) for other low-level types, such as strings.

> 4. call the static properties from a computed property?

So following from 3, I would not include factory functions for classes. If you need a factory for ARFaceTrackingConfiguration, create a factory class instead. This would probably take an enum value as parameter. However, simple functions or computed properties that return low-level data types (such as strings) would seem fine to me.

huangapple
  • 本文由 发表于 2023年7月13日 20:36:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76679462.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定