【问题标题】:Setting a computed value (struct vs class)设置计算值(结构与类)
【发布时间】:2017-06-27 09:15:17
【问题描述】:

我制作了一个简单的结构来处理 UI 背景的管理(用户可以选择使用渐变或图像)。在这个结构内部是一个名为 preference 的计算属性,它获取并将用户的偏好设置为 UserDefaults。

当我尝试使用以下代码设置 preference 属性时:

Background().preference = .gradient

我收到一个错误:“无法分配给属性:函数调用返回不可变值”

我必须改用这个:

var background = Background() background.preference = .gradient

我宁愿在最终设置属性之前不必将Background 的实例分配给变量。

我发现将Backgroundstruct 更改为class 允许我直接使用Background().preference = .gradient 设置属性。

谁能告诉我为什么会发生这种情况?在这种情况下使用class 是否比使用struct 更好,还是没关系?

struct Background {

enum Choice {
    case gradient
    case image
}

var preference: Choice {

    get {
        if let type = UserDefaults.standard.value(forKey: "background_type"), type as! String == "background" {
           return .image
        }
        return .gradient
    }

    set(value){
        if value == .image {
            UserDefaults.standard.setValue("background", forKey: "background_type")
        }else{
            UserDefaults.standard.setValue("gradient", forKey: "background_type")
        }
    }
}

【问题讨论】:

  • Background() 的每次调用都会创建一个新的Background 实例,供访问/设置UserDefault 值的唯一(临时)使用,然后丢弃特定的Background 实例。即,您当前有一个值类型,它本身不存储任何内容,仅提供对某些特定 UserDefault:s 的访问接口。也许您更愿意在这里使用单例或纯类型属性/方法(替换preference)? (请注意,让Background 成为一个类仍然存在同样的问题:您即时构建不拥有任何数据的实例)

标签: ios swift


【解决方案1】:

您并没有真正从创建结构/类的实例来包装 UserDefaults 中获得任何价值。这是一个非常常见的问题,如果你四处搜索,谷歌上有很多聪明的解决方案。对于一个非常简单的示例,您可以扩展 UserDefaults

//: Playground - noun: a place where people can play

import Cocoa


enum BackgroundChoice {
    case gradient
    case image
}

extension UserDefaults {

    var backgroundChoice: BackgroundChoice {
        get {
            if let type = string(forKey: "background_type"), type == "image" {
                return .image
            }
            return .gradient
        }

        set(value){
            if value == .image {
                setValue("background", forKey: "background_type")
            }else{
                setValue("gradient", forKey: "background_type")
            }
        }
    }

}

UserDefaults.standard.backgroundChoice = .image

我知道这并不能回答您的确切问题,但我认为如果您深入研究,您会发现有更好的解决方案。

【讨论】:

  • 我的目标是将这种类型的代码从视图控制器中移出到单独的文件中,以减小大小并提高可测试性。扩展在这方面看起来真的很有帮助。谢谢。
猜你喜欢
  • 2017-08-19
  • 1970-01-01
  • 1970-01-01
  • 2011-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多