出现“致命错误:索引超出范围":在swiftui的列表项中显示索引 [英] Got "Fatal error: Index out of range" : show index in list item for swiftui

查看:105
本文介绍了出现“致命错误:索引超出范围":在swiftui的列表项中显示索引的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

已更新:错误:如果将if闭包(if!self.showMarkedOnly || name.marked {})放在list-foreach中,为什么类型'_'没有成员'1',为什么?

Updated: error: Type '_' has no member '1', if put a if closure(if !self.showMarkedOnly || name.marked {}) inside list-foreach, why?

代码版本4:

struct Name: Identifiable, Hashable {
    var id: String = UUID().uuidString
    var name: String
    var marked: Bool
    init(_ name: String, marked: Bool = false) { self.name = name; self.marked = marked }
}

struct TestView: View {
    @State private var list: [Name] = [Name("test1"), Name("test2"), Name("test3", marked: true), Name("test4"), Name("test5", marked: true), Name("test6"), Name("test7"), Name("test8")]
    @State private var showMarkedOnly = false

    var body: some View {
        VStack{
            Toggle(isOn: $showMarkedOnly) { Text("show marked only") }
            List {
                ForEach(Array(zip(0..., list)), id: \.1.id) { index, name in
//                    if !self.showMarkedOnly || name.marked {
                        HStack {
                            Text("\(index)").foregroundColor(name.marked ? .red : .gray)
                            Spacer()
                            Text("\(name.name)")
                        }
                        .background(Color.gray.opacity(0.001))
                        .onTapGesture {
                            self.list.remove(at: index)
                        }
//                    }
                }
            }
        }
    }
}

=========

=========

已更新:我发现了代码版本2的问题,我必须提供ForEach的ID.并更新了代码版本2.

Updated: I found the issue of Code version 2, I must provide a id for ForEach. And Code version 2 updated.

我发现了一种显示索引的优美方法,它避免了self.list [index].但是我发现某些复杂代码中出现了错误类型'_'没有成员'1'".

I found a graceful way to show index, It avoids self.list[index]. But I found an error "Type '_' has no member '1'" occurred in some complex code.

代码版本3:

var body: some View {
        List {
            ForEach(Array(zip(0..., list)), id: \.1.id) { index, name in // a error occurs in some complex code: "Type '_' has no member '1'"
                HStack {
                    Text("\(index)")
                    Spacer()
                    Text("\(name.name)")
                }
                .background(Color.gray.opacity(0.001))
                .onTapGesture {
                    self.list.remove(at: index)
                }
            }
        }
    }


我显示一个列表,并删除我点击的项目.它是代码版本1,工作正常.当我使用索引(代码版本2)将索引添加到列表项时,点击后出现致命错误:索引超出范围".


I show a list, and remove the item I tapped. It's Code version 1, it works fine. When I add index into the list item using indices(Code veriosn 2), got "Fatal error: Index out of range" after tapping.

代码版本1:

struct Name: Identifiable, Hashable {
    var id: String = UUID().uuidString
    var name: String
    init(_ name: String) { self.name = name }
}

struct TestView: View {
    @State private var list: [Name] = [Name("test1"), Name("test2"), Name("test3"), Name("test4"), Name("test5"), Name("test6"), Name("test7"), Name("test8")]

    var body: some View {
        List {
            ForEach(list) { name in
                HStack {
                    Text("\(0)")
                    Spacer()
                    Text("\(name.name)")
                }
                .background(Color.gray.opacity(0.001))
                .onTapGesture {
                    self.list = self.list.filter { $0 != name }
                }
            }
        }
    }
}

代码版本2:

struct TestView: View {
    @State private var list: [Name] = [Name("test1"), Name("test2"), Name("test3"), Name("test4"), Name("test5"), Name("test6"), Name("test7"), Name("test8")]

    var body: some View {
        List {
            //ForEach(list.indices) { index in
            ForEach(list.indices, id: \.self) { index in
                HStack {
                    Text("\(index)")
                    Spacer()
                    Text("\(self.list[index].name)")
                }
                .background(Color.gray.opacity(0.001))
                .onTapGesture {
                    self.list.remove(at: index)
                }
            }
        }
    }
}

推荐答案

@State是属性包装器,它将强制定义该视图的View重新计算其主体.

@State is property wrapper, which will force the View in which it is defined to recalculate its body.

对于您而言,如果您删除索引处的项目

In your case, if you remove the item at index,

HStack {
    Text("\(index)")
    Spacer()
    Text("\(self.list[index].name)")
}
.background(Color.gray.opacity(0.001))
.onTapGesture {
     self.list.remove(at: index)
 }

HStack中的文本

the Text inside HStack

Text("\(self.list[index].name)")

崩溃,只是因为list [index]不再存在.

crash, just because list[index] doesn't exist any more.

使用

ForEach(list.indices, id:\.self) { index in ... }

代替

ForEach(list.indices) { index in ... }

将强制SwiftUI重新创建TestView(请参阅ForEach构造函数中的id:\.self)

will force SwiftUI to recreate TestView (see the id:\.self in ForEach constructor)

SwiftUI将使用@State属性包装器中包装的属性的新值来制作TestView的新副本.

SwiftUI will make fresh copy of TestView while using fresh value of property wrapped in @State property wrapper.

更新

请不要更新您的问题...

您的最后一个代码版本4完全混乱,因此我将其重写为可以复制,粘贴和运行的内容

Your last code version 4 is total mess, so I rewrote it to something you able to copy - paste - run

import SwiftUI

struct Name: Identifiable, Hashable {
    var id: String = UUID().uuidString
    var name: String
    var marked: Bool
    init(_ name: String, marked: Bool = false) { self.name = name; self.marked = marked }
}

struct ContentView: View {
    @State private var list: [Name] = [Name("test1"), Name("test2"), Name("test3", marked: true), Name("test4"), Name("test5", marked: true), Name("test6"), Name("test7"), Name("test8")]
    @State private var showMarkedOnly = false

    var body: some View {
        VStack{
            Toggle(isOn: $showMarkedOnly) {
                Text("show marked only")
            }.padding(.horizontal)
            List {
                ForEach(Array(zip(0..., list)).filter({!self.showMarkedOnly || $0.1.marked}), id: \.1.id) { index, name in
                    HStack {
                        Text("\(index)").foregroundColor(name.marked ? .red : .gray)
                        Spacer()
                        Text("\(name.name)")
                    }
                    .background(Color.gray.opacity(0.001))
                    .onTapGesture {
                        self.list.remove(at: index)
                    }
                }
            }
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

它应该看起来像

基于讨论的更新

ForEach的每个不同版本的构造器在内部使用ViewBuilder的不同功能

ForEach different versions of constructors use internally different functionality of ViewBuilder

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension ViewBuilder {

    /// Provides support for "if" statements in multi-statement closures, producing an `Optional` view
    /// that is visible only when the `if` condition evaluates `true`.
    public static func buildIf<Content>(_ content: Content?) -> Content? where Content : View

    /// Provides support for "if" statements in multi-statement closures, producing
    /// ConditionalContent for the "then" branch.
    public static func buildEither<TrueContent, FalseContent>(first: TrueContent) -> _ConditionalContent<TrueContent, FalseContent> where TrueContent : View, FalseContent : View

    /// Provides support for "if-else" statements in multi-statement closures, producing
    /// ConditionalContent for the "else" branch.
    public static func buildEither<TrueContent, FalseContent>(second: FalseContent) -> _ConditionalContent<TrueContent, FalseContent> where TrueContent : View, FalseContent : View
}

这是关于实现细节"的,希望它将在下一版本中进行记录.SwiftUI仍处于开发的早期阶段,我们必须小心.

This is about "implementation details" and hopefully it will be documented in next release. SwiftUI is still in very early stage of development, we have to be careful.

让我们尝试迫使SwiftUI遵循我们自己的方式!第一个单独的RowView

Lets try to force SwiftUI to follow our own way! First separate RowView

struct RowView: View {
    var showMarkedOnly: Bool
    var index: Int
    var name: Name
    //@ViewBuilder
    var body: some View {
        if !self.showMarkedOnly || name.marked {
            HStack {
                Text(verbatim: index.description).foregroundColor(name.marked ? .red : .gray)
                Spacer()
                Text(verbatim: name.name)
            }
            .background(Color.gray.opacity(0.001))

        }
    }
}

编译器抱怨

Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type

取消注释线条以包裹我们的身体

Uncomment the line to wrap our body

struct RowView: View {
    var showMarkedOnly: Bool
    var index: Int
    var name: Name
    @ViewBuilder
    var body: some View {
        if !self.showMarkedOnly || name.marked {
            HStack {
                Text(verbatim: index.description).foregroundColor(name.marked ? .red : .gray)
                Spacer()
                Text(verbatim: name.name)
            }
            .background(Color.gray.opacity(0.001))

        }
    }
}

现在我们可以按照您喜欢的方式使用代码了:-)

Now we can use the code the way you like :-)

struct ContentView: View {
    @State private var list: [Name] = [Name("test1"), Name("test2"), Name("test3", marked: true), Name("test4"), Name("test5", marked: true), Name("test6"), Name("test7"), Name("test8")]
    @State private var showMarkedOnly = false

    var body: some View {
        VStack{
            Toggle(isOn: $showMarkedOnly) {
                Text("show marked only")
            }.padding(.horizontal)
            List {
                ForEach(Array(zip(0..., list)), id: \.1.id) { (index, name) in
                    RowView(showMarkedOnly: self.showMarkedOnly, index: index, name: name).onTapGesture {
                    self.list.remove(at: index)
                }
                }
            }
        }
    }
}

最终结果现在使用 buildIf< Content> 构造,并且所有代码再次起作用(结果与上面显示的完全一样)

The final result uses now buildIf<Content> construct and all code works again (the result looks exactly the same as shown above)

这篇关于出现“致命错误:索引超出范围":在swiftui的列表项中显示索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆