SwiftUI CS193P - 不能在属性初始化程序中使用实例成员“卡片”;属性初始化程序在“自我”可用之前运行

Posted

技术标签:

【中文标题】SwiftUI CS193P - 不能在属性初始化程序中使用实例成员“卡片”;属性初始化程序在“自我”可用之前运行【英文标题】:SwiftUI CS193P - Cannot use instance member 'card' within property initializer; property initializers run before 'self' is available 【发布时间】:2020-11-21 00:42:25 【问题描述】:

我关注Stanfords' CS193p Developing Apps for ios online course。 我正在使用 Xcode 11.5。 (我没有更新,因为这是课程讲师(Paul Heagarty)正在使用的版本。)

我正在尝试执行Assignment 3 (Set Game)。我知道我的代码可能在很多地方都写得不好,但我稍后会改进它,现在我只是想让它没有错误地工作。 我目前无法修复的错误是:

var shading: SetGameModel.Card.Shading = card.shading //Error: Cannot use instance member 'card' within property initializer; property initializers run before 'self' is available

这里是完整的查看代码: 如果您还需要 ViewModel、Model 或其他一些文件来帮助我修复它,请告诉我:-)

请尝试以某种方式帮助我修复它,我作为初学者会理解 ????

//
//  SetGameView.swift
//  TheSetGame
//

import SwiftUI

struct SetGameView: View 
    
    @ObservedObject var viewModel: SetGameViewModel
    
    var body: some View 
            Grid(viewModel.cards)  card in
                CardView(card: card, shading: .solid).onTapGesture 
                    self.viewModel.choose(card: card)
                
            
        .padding()
        .foregroundColor(Color.orange)
    


struct CardView: View 
    var card: SetGameModel.Card
    // Shape features (numberOfShapes, shape, shading, color):
    var numberOfShapes: Int 
        switch card.numberOfShapes 
        case .one:
            return 1
        case .two:
            return 2
        case .three:
            return 3
        
    
    
    var shading: SetGameModel.Card.Shading = card.shading //Error: Cannot use instance member 'card' within property initializer; property initializers run before 'self' is available
    var isFilled: Bool  shading == .solid ? true : false 
    var isStriped: Bool  shading == .striped ? true : false 
    
    var color: Color 
        switch card.color 
        case .green:
            return Color.green
        case .purple:
            return Color.purple
        case .red:
            return Color.red
        
    
    
    var body: some View 
        ZStack 
            RoundedRectangle(cornerRadius: 10.0).fill(Color.white)
            RoundedRectangle(cornerRadius: 10.0)
                .stroke(lineWidth: card.isChosen ? 6 : 3)
                .foregroundColor(card.isChosen ? Color.red : Color.orange)
            VStack 
                ForEach(0..<numberOfShapes)  index in
                    if self.card.shape == .diamond 
                        Diamond()//.scale(0.75)
                    
                    if self.card.shape == .squiggle 
                        Rectangle()//.scale(0.75)
                    
                    if self.card.shape == .oval 
                        Ellipse()//.scale(0.75)
                    
                
            
            .foregroundColor(self.color)
            .padding()
        
        .aspectRatio(2/3, contentMode: .fit)
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        SetGameView(viewModel: SetGameViewModel())
    

【问题讨论】:

var shading: SetGameModel.Card.Shading 更改为lazy var shading: SetGameModel.Card.Shading 是否有效? 【参考方案1】:

这听起来有点存在主义,但编译器会抱怨,因为您试图将 shading 设置为一个尚不存在的值。当您第一次在视图中设置变量的值时,它们实际上并不存在。您正在告诉编译器它们将是什么,但编译器坚持认为您所说的变量将实际存在。

有一些方法可以解决这个问题,例如 George E. 建议使用惰性 var。我不想走那条路,因为那超出了初学者的范围。为了您的目的,只要知道,当您定义一个变量时,它必须给出一个实际值。编译器不会抱怨var x = 1,因为它知道 1 是什么,而且它已经存在。

您的确切错误表明您无法使用实例card,因为它在您尝试使用它时尚未初始化。换句话说,当您尝试分配它时,它没有任何价值,例如 card.shadingshading

现在,话虽如此,您为什么需要阴影?你想要的阴影不是总是card.shading 吗?与其创建一个单独的变量,不如使用你所拥有的。学会爱上点符号并保持简单。

在您最初的问题之外,最后要考虑的是,您有一个没有任何状态变量的视图。如果您尝试更改未标记为@State 的变量,您的编译器将在运行时报错。您创建的是一个固定视图,而不是可以更改或更新的视图。

【讨论】:

【参考方案2】:

替换那些行

var shading: SetGameModel.Card.Shading = card.shading
var isFilled: Bool  shading == .solid ? true : false 
var isStriped: Bool  shading == .striped ? true : false 

var isFilled: Bool 
    return card.shading == .solid

var isStriped: Bool 
    return card.shading == .striped

在创建该类或结构的实例时,类和结构必须将其所有存储的属性设置为适当的初始值。存储的属性不能处于不确定状态。

阅读此文档以清楚了解为什么不能使用 card.shading。 https://docs.swift.org/swift-book/LanguageGuide/Initialization.html

【讨论】:

【参考方案3】:

如果您有 preperties 初始化的依赖项,您需要在 init 中执行此操作。

struct CardView: View 
    var card: SetGameModel.Card
    // ... other code
    var shading: SetGameModel.Card.Shading = card.shading

    init(card: SetGameModel.Card, ) 
       self.card = card
       self.shading = card.shading         // << here !!
    

    // ... other code

【讨论】:

以上是关于SwiftUI CS193P - 不能在属性初始化程序中使用实例成员“卡片”;属性初始化程序在“自我”可用之前运行的主要内容,如果未能解决你的问题,请参考以下文章

CS193p - 2015 年冬季 - 计算器故事板自动布局

SwiftUI Maps - 不能在属性初始化器中使用实例成员;属性初始化程序在 'self' 可用之前运行

结构中的 Swift/SwiftUI 属性初始化程序错误

SwiftUI 数组列表

SwiftUI:自定义SearchBar

在 SwiftUI 中用另一个 @State 属性值初始化 @State 属性