因索引超出范围而崩溃——尽管我确定索引没有超出范围

时间:2021-07-15 22:18:30

标签: swiftui

我有一个父视图,其子视图是数组的任何给定索引。通过点击增加或减少存储在 State 属性中的索引的按钮来滚动数组的索引。

然而,当视图第一次初始化时,即使 State 的初始值始终为 0,我也会崩溃。

这是怎么回事?

代码可以复制粘贴重现错误

import SwiftUI

struct ContentView: View {
    @State private var shouldShowQuotes = false
    var body: some View {
        ZStack {
            Color.orange
            VStack {
                Button(action: showQuotes){
                    Text("Get Quotes").bold()
                        .frame(maxWidth: 300)
                }
                   //  .controlProminence(.increased) //Safe to uncomment if Xcode 13
                    // .buttonStyle(.bordered) 
                    // .controlSize(.large)
            }
            .fullScreenCover(isPresented: $shouldShowQuotes) {
                QuoteScreen()
            }
        }.ignoresSafeArea()
    }
    private func showQuotes() {
        self.shouldShowQuotes.toggle()
    }
}

struct QuoteScreen: View {
    @State private var quoteIndex = 0
    var currentQuote: Quote {
        return dummyData[quoteIndex]
    }
    var body: some View {
        ZStack {
            Color.orange
            VStack {
                QuoteView(quote: currentQuote)
                Spacer()
                HStack {
                    Button(action: degress) {
                        Image(systemName: "arrow.left.square.fill")
                            .resizable()
                        .frame(width: 50, height: 50)
                    }
                    Spacer()
                    Button(action: progress) {
                        Image(systemName: "arrow.right.square.fill")
                            .resizable()
                        .frame(width: 50, height: 50)
                    }
                }
                .padding(28)
                    //.buttonStyle(.plain) Safe to uncomment if Xcode 13
                    
            }
        }.ignoresSafeArea()
    }
    private func progress() {
    quoteIndex += 1
    }
    
    private func degress() {
        quoteIndex -= 1
    }
}

struct QuoteView: View {
    @State private var showQuotes = false
    let quote: Quote
    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 25)
                .stroke(lineWidth: 2)
            VStack {
                Text(quote.quote)
                frame(maxWidth: 300)
                Text(quote.author)
                    .frame(maxWidth: 300, alignment: .trailing)
                    .foregroundColor(.secondary)
            }
            
        }.navigationBarHidden(true)
        .frame(height: 400)
            .padding()
    }
}


let dummyData = [Quote(quote: "The apple does not fall far from the tree", author: "Lincoln", index: 1),
                Quote(quote: "Not everything that can be faced can be changed, but be sure that nothing can change until it is faced", author: "Unknown", index: 2),
                 Quote(quote: "Actions are but intentions", author: "Muhammad", index: 3)
    ]

struct Quote: Codable {
    let quote: String
    let author: String
    let index: Int
}

2 个答案:

答案 0 :(得分:1)

使用数组时,您必须始终检查所选索引处的元素是否存在。这是如何 我测试并修改了您的代码以使其正常工作。 (注意:虽然这只是对 dummyData 的测试,但您需要决定是滚动数组索引还是 Quote-index 值,并进行相应调整)

import SwiftUI


@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

let dummyData = [
    Quote(quote: "the index zero quote", author: "silly-billy", index: 0),
    Quote(quote: "The apple does not fall far from the tree", author: "Lincoln", index: 1),
    Quote(quote: "Not everything that can be faced can be changed, but be sure that nothing can change until it is faced", author: "Unknown", index: 2),
    Quote(quote: "Actions are but intentions", author: "Muhammad", index: 3)
]

struct ContentView: View {
    @State private var shouldShowQuotes = false
    var body: some View {
        ZStack {
            Color.orange
            VStack {
                Button(action: showQuotes){
                    Text("Get Quotes").bold()
                        .frame(maxWidth: 300)
                }
                //  .controlProminence(.increased) //Safe to uncomment if Xcode 13
                // .buttonStyle(.bordered)
                // .controlSize(.large)
            }
            .fullScreenCover(isPresented: $shouldShowQuotes) {
                QuoteScreen()
            }
        }.ignoresSafeArea()
    }
    private func showQuotes() {
        self.shouldShowQuotes.toggle()
    }
}

struct QuoteScreen: View {
    @State private var quoteIndex = 0
    @State var currentQuote: Quote = dummyData[0]  // <--- here, do not use "quoteIndex"

    var body: some View {
        ZStack {
            Color.orange
            VStack {
                QuoteView(quote: $currentQuote) // <--- here
                Spacer()
                HStack {
                    Button(action: degress) {
                        Image(systemName: "arrow.left.square.fill")
                            .resizable()
                            .frame(width: 50, height: 50)
                    }
                    Spacer()
                    Button(action: progress) {
                        Image(systemName: "arrow.right.square.fill")
                            .resizable()
                            .frame(width: 50, height: 50)
                    }
                }
                .padding(28)
                //.buttonStyle(.plain) Safe to uncomment if Xcode 13
                
            }
        }.ignoresSafeArea()
    }
    // you will have to adjust this to your needs
        private func progress() {
    let prevValue = quoteIndex
    quoteIndex += 1
    if let thisQuote = dummyData.first(where: { $0.index == quoteIndex}) { // <--- here
        currentQuote = thisQuote
    } else {
        quoteIndex = prevValue
    }
}
// you will have to adjust this to your needs
private func degress() {
    let prevValue = quoteIndex
    quoteIndex -= 1
    if let thisQuote = dummyData.first(where: { $0.index == quoteIndex}) { // <--- here
        currentQuote = thisQuote
    } else {
        quoteIndex = prevValue
    }
}
}

struct QuoteView: View {
    @State private var showQuotes = false
    @Binding var quote: Quote // <--- here
    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 25)
                .stroke(lineWidth: 2)
            VStack {
                Text(quote.quote)
                    .frame(maxWidth: 300) // <--- here missing leading "."
                Text(quote.author)
                    .frame(maxWidth: 300, alignment: .trailing)
                    .foregroundColor(.secondary)
            }
            
        }.navigationBarHidden(true)
            .frame(height: 400)
            .padding()
    }
}

struct Quote: Identifiable {
    let id = UUID()
    var quote: String
    var author: String
    var index: Int
}

答案 1 :(得分:1)

此崩溃不是由数组访问引起的,而是由代码中的拼写错误引起的。你可以看到,如果你在模拟器中运行它并查看堆栈跟踪。它在 SwiftUI 的内部陷入无限循环。原因是 frame 修饰符前缺少点:


struct QuoteView: View {
    @State private var showQuotes = false
    let quote: Quote
    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 25)
                .stroke(lineWidth: 2)
            VStack {
                Text(quote.quote)
                frame(maxWidth: 300)  << !!!!! missing dot
                Text(quote.author)
                    .frame(maxWidth: 300, alignment: .trailing)
                    .foregroundColor(.secondary)
            }
            
        }.navigationBarHidden(true)
        .frame(height: 400)
            .padding()
    }
}

这会在 QuoteView 而非 Text 上调用 frame 方法 - 这是无效的操作。