Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/102.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
Ios 设置计算值(结构与类)_Ios_Swift - Fatal编程技术网

Ios 设置计算值(结构与类)

Ios 设置计算值(结构与类),ios,swift,Ios,Swift,我制作了一个简单的结构来处理UI背景的管理(用户可以选择使用渐变或图像)。此结构中有一个名为preference的计算属性,用于获取用户的首选项并将其设置为UserDefaults 当我尝试使用以下代码设置首选项属性时: Background().首选项=.gradient 我收到一个错误:“无法分配给属性:函数调用返回不可变值” 我必须用这个来代替: var background=background() background.preference=.gradient 我希望在最终设置属性之前

我制作了一个简单的结构来处理UI背景的管理(用户可以选择使用渐变或图像)。此结构中有一个名为
preference
的计算属性,用于获取用户的首选项并将其设置为UserDefaults

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

Background().首选项=.gradient

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

我必须用这个来代替:

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

我希望在最终设置属性之前,不必将
Background
的实例分配给变量

我发现将
Background
struct
更改为
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")
        }
    }
}

将一个结构/类的实例仅仅包装为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

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

每次调用
Background()
都会创建一个新的
Background
实例,用于唯一(临时)访问/设置
UserDefault
值,在你扔掉特定的
Background
实例之后。也就是说,您当前有一个值类型,它本身不存储任何内容,只提供对某些特定
UserDefault
:s的访问接口。也许您更愿意在这里使用单例或纯类型属性/方法(以替换
首选项
)?(请注意,让
Background
成为一个类仍然存在相同的问题:您动态构造实例,而实例本身并不拥有任何数据)我的目标是将这种类型的代码从视图控制器移出到单独的文件中,以减少大小并提高可测试性。在这方面,扩展看起来非常有用。谢谢