我有一个父视图,其子视图是数组的任何给定索引。通过点击增加或减少存储在 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
}
答案 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 方法 - 这是无效的操作。