“不能分配给这个表达式的结果”变量引起的错误(var)

时间:2015-07-21 14:51:01

标签: swift subclass enumeration scenekit

我定义了以下子类,其主要属性链接到枚举:

let NumberOfColors: UInt32 = 6

enum SphereColor: Int, Printable {
case Red = 0, Yellow, Blue, Green, Purple, White

var sphereName: String {
    switch self {
    case .Red:
        return "red"
    case .Yellow:
        return "yellow"
    case .Blue:
        return "blue"
    case .Green:
        return "green"
    case .Purple:
        return "purple"
    case .White:
        return "white"
    }
}

var description: String {
    return self.sphereName
}

static func random() -> SphereColor {
    return SphereColor(rawValue: Int(arc4random_uniform(NumberOfColors - 1)))!
    }
}


class Sphere: SCNSphere {
var color : SphereColor

init(radius: CGFloat, color: SphereColor) {
    self.color = color
    super.init()
    switch color.rawValue as Int {
    case 0:
        self.firstMaterial?.diffuse.contents = UIColor.redColor()
    case 1:
        self.firstMaterial?.diffuse.contents = UIColor.yellowColor()
    case 2:
        self.firstMaterial?.diffuse.contents = UIColor.blueColor()
    case 3:
        self.firstMaterial?.diffuse.contents = UIColor.greenColor()
    case 4:
        self.firstMaterial?.diffuse.contents = UIColor.purpleColor()
    case 5:
        self.firstMaterial?.diffuse.contents = UIColor.whiteColor()
    default:
        break
    }
}

required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
    }
}

使用

实例化它
let sphere = Sphere(radius: radius, color: SphereColor.random()) 

let sphereNode = SCNNode(geometry: sphere)

工作正常,但是当我选择其中一个节点并尝试使用

更改其颜色属性时
// node selection...
var geom = node.geometry! as! Sphere
geom.color.rawValue = 5

我得到“无法分配给这个表达式的结果”错误,但是我没有将color属性声明为常量,并且不明白为什么会发生这种情况。我假设我在相对于Sphere类的代码中犯了一些基本错误,对于这可能是什么想法?

编辑:使用

geom.color = SphereColor(rawValue: 5)!
正如Martin R所说,允许我构建并运行我的代码但是球体的颜色没有改变,这让我觉得我的子类声明仍然有问题。

2 个答案:

答案 0 :(得分:1)

rawValue是只读属性,您无法分配新值 它。您必须从中创建SphereColor 原始值并将其分配给color属性:

geom.color = SphereColor(rawValue: 5)!

或者如果任何机会原始值可能超出范围 并且不存在匹配的颜色:

if let color = SphereColor(rawValue: 5) {
    geom.color = color
}

答案 1 :(得分:0)

支持@MartinR修复第一个问题,但我对其余部分的回答太大而无法发表评论。

如上所述,rawValue是枚举的只读属性。枚举为value types,因此您无法更改"实例"的值在枚举中,您创建了一个新值。 (将枚举想象成奇特的数字。你不能将7 本身改为另一个数字,你改变一个保持值为7的变量来保存另一个值。)从相应的值创建一个枚举值原始类型,使用init(rawValue:)初始值设定项。

您的第二个问题是您正在更新模型(以概念/语义方式告诉您您认为您的球是什么颜色的部分),但您要重新设置该模型的视觉表示(只有在创建Sphere时,才能看到SceneKit的东西),而不是在设置color属性时。如果你想让模型和视图保持同步,你需要做到这一点。

您已经拥有在初始化程序中将Color转换为SceneKit材质颜色的代码。因为您可以从其他地方调用它,然后您可以在模型更改时使用它来更新您的视图 - 例如,使用property observer

以上,以及其他一些改进:

class Sphere: SCNSphere {

    func setMaterialColor(sphereColor: SphereColor) {
        let color: UIColor
        // Switch on the enum, not the int.
        // That way the compiler can check exhaustiveness,
        // and you don't need a dead default case.
        switch sphereColor {
            case .Red:
                // Use a temporary for the color choice so 
                // you're only setting the material property once.
                color = UIColor.redColor()
            case .Yellow:
                color = UIColor.yellowColor()
            case .Blue:
                color = UIColor.blueColor()
            case .Green:
                color = UIColor.greenColor()
            case .Purple:
                color = UIColor.purpleColor()
            case .White:
                color = UIColor.whiteColor()
        }
        // Force-unwrap firstMaterial -- we "know" it should be non-nil,
        // so it's better to find out the hard way if something weird has happened.
        // (Either that or test the optional so you can manage failure specifically.)
        self.firstMaterial!.diffuse.contents = color
    }

    var color : SphereColor {
        didSet {
            self.setMaterialColor(color)
        }
    }

    init(radius: CGFloat, color: SphereColor) {
        self.color = color
        super.init()
        self.setMaterialColor(color)
    }

    required init(coder aDecoder: NSCoder) { /* ... */ }
}