错误不能在属性初始化程序中使用实例成员“xxx”

Posted

技术标签:

【中文标题】错误不能在属性初始化程序中使用实例成员“xxx”【英文标题】:Error Cannot use instance member 'xxx' within property initializer 【发布时间】:2019-12-03 00:14:42 【问题描述】:

26-07-19

随着观看 WWDC 视频的进展,我将更新我的代码。我的数据模型是:

struct Egg: Identifiable 
    var id = UUID()
    var thumbnailImage: String
    var day: String
    var date: String
    var text: String
    var imageDetail: String
    var weight: Double


#if DEBUG
let testData = [

    Egg(thumbnailImage: "Dag-1", day: "1.circle", date: "7 augustus 2019", text: "Kippen leggen iedere dag een ei.", imageDetail: "Day-1", weight: 35.48),

    Egg(thumbnailImage: "Dag-2", day: "2.circle", date: "8 augustus 2019", text: "Kippen leggen iedere dag een ei.", imageDetail: "Day-2", weight: 35.23),

    Egg(thumbnailImage: "Dag-3", day: "3.circle", date: "9 augustus 2019", text: "Kippen leggen iedere dag een ei.", imageDetail: "Day-3", weight: 34.92)

Etc, etc
]

我有一个 TabbedView、一个 ContentView、一个 ContentDetail 和几个其他视图(用于设置等)。 ContentView 的代码是:

struct ContentView : View 
    var eggs : [Egg] = []

    var body: some View 
        NavigationView 
            List(eggs)  egg in
                EggCell(egg: egg)
            
            .padding(.top, 10.0)
            .navigationBarTitle(Text("Egg management"), displayMode: .inline)
        
    


#if DEBUG
struct ContentView_Previews : PreviewProvider 
    static var previews: some View 
        ContentView(eggs: testData)
    

#endif

struct EggCell : View 
    let egg: Egg

    var body: some View 

        return NavigationLink(destination: ContentDetail(egg: egg)) 

            ZStack 

                HStack(spacing: 8.0) 

                    Image(egg.thumbnailImage)
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .padding(.leading, -25)
                        .padding(.top, -15)
                        .padding(.bottom, -15)
                        .padding(.trailing, -25)
                        .frame(width: 85, height: 61)

                    VStack 
                        Image(systemName: egg.day)
                            .resizable()
                            .frame(width: 30, height: 22)
                            .padding(.leading, -82)

                        Spacer()
                    
                    .padding(.leading)

                    VStack 
                        Text(egg.date)
                            .font(.headline)
                            .foregroundColor(Color.gray)
                        Text(egg.weight.clean)
                            .font(.title)

                    

                
            
        
    


extension Double 
    var clean: String 
        return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(format: "%.2f", self)
    

ContentDetail 的代码是:

struct ContentDetail : View 
    let egg: Egg

    @State private var photo = true
    @State private var calculated = false
    @Binding var weight: Double

    var body: some View 

        VStack (alignment: .center, spacing: 10) 

            Text(egg.date)
                .font(.title)
                .fontWeight(.medium)
                .navigationBarTitle(Text(egg.date), displayMode: .inline)

            ZStack (alignment: .topLeading) 

                Image(photo ? egg.imageDetail : egg.thumbnailImage)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .background(Color.black)
                    .padding(.trailing, 0)
                    .tapAction  self.photo.toggle() 

                VStack 

                    HStack 
                        Image(systemName: egg.day)
                            .resizable()
                            .padding(.leading, 10)
                            .padding(.top, 10)
                            .frame(width: 50, height: 36)
                            .foregroundColor(.white)

                        Spacer()

                        Image(systemName: photo ?  "photo" : "wand.and.stars")
                            .resizable()
                            .padding(.trailing, 10)
                            .padding(.top, 10)
                            .frame(width: 50, height: 36)
                            .foregroundColor(.white)

                    

                    Spacer()

                    HStack 
                        Image(systemName: "arrow.left.circle")
                            .resizable()
                            .padding(.leading, 10)
                            .padding(.bottom, 10)
                            .frame(width: 50, height: 50)
                            .foregroundColor(.white)

                        Spacer()

                        Image(systemName: "arrow.right.circle")
                            .resizable()
                            .padding(.trailing, 10)
                            .padding(.bottom, 10)
                            .frame(width: 50, height: 50)
                            .foregroundColor(.white)

                    
                
            

            Text("the weight is: \(egg.weight) gram")
                .font(.headline)
                .fontWeight(.bold)

            ZStack 

                RoundedRectangle(cornerRadius: 10)
                    .padding(.top, 45)
                    .padding(.bottom, 45)
                    .border(Color.gray, width: 5)
                    .opacity(0.1)

                HStack 

                    Spacer()

                    DigitPicker(digitName: "tens", digit: $weight.tens)
                    DigitPicker(digitName: "ones", digit: $weight.ones)

                    Text(".")
                        .font(.largeTitle)
                        .fontWeight(.black)
                        .padding(.bottom, 10)

                    DigitPicker(digitName: "tenths", digit: $weight.tenths)
                    DigitPicker(digitName: "hundredths", digit: $weight.hundredths)

                    Spacer()

                    
                

            Toggle(isOn: $calculated) 
                Text(calculated ? "This weight is calculated." : "This weight is measured.")
            

            Text(egg.text)
                .lineLimit(2)
                .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                .padding(.leading, 6)

            Spacer()

        
        .padding(6)

    


#if DEBUG
struct ContentDetail_Previews : PreviewProvider 
    static var previews: some View 
        NavigationView  ContentDetail(egg: testData[0]) 
    

#endif


struct DigitPicker: View 
    var digitName: String
    @Binding var digit: Int

    var body: some View 
        VStack 
            Picker(selection: $digit, label: Text(digitName)) 
                ForEach(0 ... 9) 
                    Text("\($0)").tag($0)
                
            .frame(width: 60, height: 110).clipped()
        
    


fileprivate extension Double 
    var tens: Int 
        get  sigFigs / 1000 
        set  replace(tens: newValue)  
    

    var ones: Int 
        get  (sigFigs / 100) % 10 
        set  replace(ones: newValue) 
    

    var tenths: Int 
        get  (sigFigs / 10) % 10 
        set  replace(tenths: newValue) 
    

    var hundredths: Int 
        get  sigFigs % 10 
        set  replace(hundredths: newValue) 
    

    private mutating func replace(tens: Int? = nil, ones: Int? = nil, tenths: Int? = nil, hundredths: Int? = nil) 
        self = Double(0
            + 1000 * (tens ?? self.tens)
            + 100 * (ones ?? self.ones)
            + 10 * (tenths ?? self.tenths)
            + (hundredths ?? self.hundredths)) / 100.0
    

    private var sigFigs: Int 
        return Int((self * 100).rounded(.toNearestOrEven))
    

我仍然遇到的编译器错误是:

    在 ContentView 中,在 NavigationLink 下方:缺少参数 调用中的参数“权重” 在 ContentDetail 中,在 NavigationView:缺少参数的参数 通话中的“体重” 在 ContentDetail 中,#endif 之后:缺少参数的参数 通话中的“体重”

25-07-19

以下代码是列表详细信息视图的一部分。 var 'weight' 来自 List 通过 'NavigationLink' 语句。在这段代码中,我将其声明为“35.48”,但 NavigationLink 填写了它的实际值。

我想用 compactMap 语句创建一个数组 [3, 5, 4, 8]。这在 Playground 中可以正常工作。值转到 4 个不同的选择器(在 HStack 中)。

import SwiftUI
import Foundation

    struct ContentDetail : View 

        var weight : Double = 35.48
        var weightArray = "\(weight)".compactMap  Int("\($0)") 

        @State var digit1 = weightArray[0] // error
        @State var digit2 = weightArray[1] // error
        @State var digit3 = weightArray[2] // error
        @State var digit4 = weightArray[3] // error

        var body: some View 

            VStack (alignment: .center, spacing: 10) 

                Text(weight)
                    .font(.title)
                    .fontWeight(.medium)

    etc etc

我在属性初始化程序中收到错误“无法使用实例成员“weightArray”;属性初始化程序在“self”可用之前运行。

如果我使用以下代码,它可以正常工作(对于第一个列表元素):

import SwiftUI
import Foundation

    struct ContentDetail : View 

        var weight : Double = 35.48
        var weightArray = [3, 5, 4, 8]

        @State var digit1 = 3
        @State var digit2 = 5
        @State var digit3 = 4
        @State var digit4 = 8

        var body: some View 

            VStack (alignment: .center, spacing: 10) 

                Text(weight)
                    .font(.title)
                    .fontWeight(.medium)

    etc etc

什么是正确的 SwiftUI 方法,为什么?

【问题讨论】:

我试过 'lazy var weightArray = "(weight)".compactMap Int("($0)") ' 但是状态变量仍然在抱怨(即使我也让他们变得懒惰)。 您最终是否将weight 变量删除为更“有状态”的变量?如果是这样,为什么不现在做呢?事实上,如果您认为您将使用某种模型,也许您现在应该节省一些时间 - 将您的逻辑包含在其中并适当地将您的视图绑定到它。今天一大早我终于看到了这个视频,不知道它是否可以帮助你调用 SwiftUI 背后的 Swift:youtube.com/watch?v=2eK8voQeokk&feature=youtu.be 【参考方案1】:

确实,属性初始化器不能引用同一容器中的另一个属性。您必须在 init 中初始化您的属性。

struct ContentDetail: View 

    var weight: Double
    var weightArray: [Int]

    @State var digit1: Int
    @State var digit2: Int
    @State var digit3: Int
    @State var digit4: Int

    init(weight: Double) 
        self.weight = weight
        weightArray = "\(weight)".compactMap  Int("\($0)") 
        _digit1 = .init(initialValue: weightArray[0])
        _digit2 = .init(initialValue: weightArray[1])
        _digit3 = .init(initialValue: weightArray[2])
        _digit4 = .init(initialValue: weightArray[3])
    

但我怀疑你打破数字是因为你想让用户单独编辑它们,像这样:

如果这是您想要的,您不应该为每个数字设置单独的 @State 属性。相反,weight 应该是 @Binding,并且每个数字都应该有一个单独的可变属性。

首先,扩展Double 让您可以访问数字:

fileprivate extension Double 
    var tens: Int 
        get  sigFigs / 1000 
        set  replace(tens: newValue)  
    

    var ones: Int 
        get  (sigFigs / 100) % 10 
        set  replace(ones: newValue) 
    

    var tenths: Int 
        get  (sigFigs / 10) % 10 
        set  replace(tenths: newValue) 
    

    var hundredths: Int 
        get  sigFigs % 10 
        set  replace(hundredths: newValue) 
    

    private mutating func replace(tens: Int? = nil, ones: Int? = nil, tenths: Int? = nil, hundredths: Int? = nil) 
        self = Double(0
            + 1000 * (tens ?? self.tens)
            + 100 * (ones ?? self.ones)
            + 10 * (tenths ?? self.tenths)
            + (hundredths ?? self.hundredths)) / 100.0
    

    private var sigFigs: Int 
        return Int((self * 100).rounded(.toNearestOrEven))
    

然后,将ContentDetailweight 属性更改为@Binding 并去掉其他属性:

struct ContentDetail: View 
    @Binding var weight: Double

    var body: some View 
        HStack 
            DigitPicker(digitName: "tens", digit: $weight.tens)
            DigitPicker(digitName: "ones", digit: $weight.ones)
            DigitPicker(digitName: "tenths", digit: $weight.tenths)
            DigitPicker(digitName: "hundredths", digit: $weight.hundredths)
        
    


struct DigitPicker: View 
    var digitName: String
    @Binding var digit: Int

    var body: some View 
        VStack 
            Picker(selection: $digit, label: Text(digitName)) 
                ForEach(0 ... 9) 
                    Text("\($0)").tag($0)
                
            .frame(width: 60, height: 110).clipped()
        
    

这是在操场上测试它所需的其余代码,这就是我生成上面这张图片的方式:

import PlaygroundSupport

struct TestView: View 
    @State var weight: Double = 35.48

    var body: some View 
        VStack(spacing: 0) 
            Text("Weight: \(weight)")
            ContentDetail(weight: $weight)
                .padding()
        
    


let host = UIHostingController(rootView: TestView())
host.preferredContentSize = .init(width: 320, height: 240)
PlaygroundPage.current.liveView = host

【讨论】:

感谢您的所有努力,Rob。顺便说一句,我刚刚读了你关于“处理日期”的文章……我还在学习,而且速度不是那么快。我有一个更简单的扩展来“清理我的双打”... extension Double var clean: String return self.truncatingRemainder(dividingBy: 1) == 0 ?字符串(格式:“%.0f”,自我):字符串(格式:“%.2f”,自我) 好答案。我仍然会推荐我做的视频。 mapfflatmapf(对我来说)似乎会删除大量代码,同时让事情更容易理解。 我将您的代码复制到了项目的副本中,Rob。我遇到了几个编译器错误。在 IF Debug Xcode 中建议通过 'Insert 'weight #>' 修复 下一步...在列表视图中,我得到一个“表达式类型不明确,没有更多上下文”。该错误出现在 NavigationLink(destination: ContentDetail(weight: item.weight, text: item.text, imageList: item.imageList, day: item.day, date: item.date, imageDetail: item.imageDetail)) 之后 如果你想要一个PreviewProvider,它需要为weight 传递一个BindingContentDetail 初始化器。我没有遇到这个问题,因为我在操场而不是预览画布上进行了测试,因为我现在被引导到 Mojave。

以上是关于错误不能在属性初始化程序中使用实例成员“xxx”的主要内容,如果未能解决你的问题,请参考以下文章

Swift 不能在属性初始化器中使用实例成员

不能在属性初始值设定项中使用实例成员 '';属性初始化程序在 'self' 可用之前运行

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

无法在属性初始化程序中使用实例成员,将变量设置为惰性不起作用

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

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