SwiftUI 참고 : 상위 뷰에서 목록을 삭제하면 하위 뷰가 index out of range로 떨어집니다.
14366 단어 SwiftUI
우선 현재의 메모.
충돌하는 예
List
중 ForEach
및 .onDelete
또는 .onMove
설정 import Foundation
import SwiftUI
// お店は商品を複数持っている
struct Shop {
var name: String
var items: [Item]
}
// 商品。とりあえず名前だけ。
struct Item: Identifiable {
var id = UUID()
var name: String
}
// 親ビュー
struct SimpleList: View {
// サンプルデータ。
@State var shop = Shop(
name: "くだもの屋さん",
items: [
Item(name: "りんご"),
Item(name: "ばなな"),
Item(name: "みかん")
]
)
var body: some View {
VStack {
Text(shop.name).font(.title)
HStack(spacing:20) {
Button(action: onAdd){ Image(systemName: "plus") }
Spacer()
EditButton()
}
List {
// お店の商品でForEach
ForEach(shop.items){ item in
// 子ビューにぜんぶ任せる、バインドで!
SimpleSubView(item: $shop.items[id2index(item.id)])
}
// 移動・削除の処理
.onMove(perform: onMove)
.onDelete(perform: onDelete)
}
}
.padding()
}
// IDからリストのindex番号取得
func id2index(_ id: UUID) -> Int {
return shop.items.firstIndex(where: { $0.id == id })!
}
// お店の商品追加、移動、削除
func onAdd() {
let newItem = Item(name: "new item")
shop.items.append(newItem)
}
func onMove(_ iset: IndexSet, _ newOffset: Int) {
shop.items.move(fromOffsets: iset, toOffset: newOffset)
}
func onDelete(_ iset: IndexSet) {
shop.items.remove(atOffsets: iset)
}
}
// 子ビュー
struct SimpleSubView: View {
// 編集したり色々する予定でバインドで受け取っている
@Binding var item: Item
var body: some View {
Text(item.name) // が、今はとりあえず、単純に表示
}
}
동작 스크린샷
오류 메시지
Fatal error: Index out of range: file Swift/ContiguousArrayBuffer.swift, line 444
(타임 스탬프) (프로젝트 이름)[9600:1174243] Fatal error: Index out of range: file Swift/ContiguousArrayBuffer.swift, line 444
(lldb)
인덱스가 범위외…?
충돌하지 않는 예
구구나 시험해 보았던 것은,
ForEach(リスト, id:_)
하고 있는 바람에 명시적으로 id를 지시하라」적인 기사를 발견했지만, 지금 현재(2021년 1월) id 지정해도 관계없었다. 아이 뷰에 건네주지 않고, 직접 ForEach내에 쓰면 크래쉬 하지 않는다
ForEach 안에 오랫동안 코드를 쓰는 것은 나중에 보기 힘들고 후회할 것 같다.
그래서, 아이 뷰에는 값으로 건네주면서, 어떻게든 아이 뷰로부터 원래의 리스트를 갱신하는 방향으로 생각했다.
목록은 목록에서 별도로 바인딩으로 전달했습니다.
앞의 코드에서 변경된 사항
// 親ビューのForEachの中
// SimpleSubView(item: $shop.items[id2index(item.id)])
SimpleSubView(item: item, items: $shop.items)
// 親の id2index(UUID)->Int は不要になる。
// 子ビュー
struct SimpleSubView: View {
@State var item: Item // 普通に値で受け取る
@Binding var items: [Item] // 加えてリスト全体をバインドで受け取る
var body: some View {
HStack {
// 値で受け取ったitemで編集。コミット時にバインドされたリストに反映
TextField("name", text: $item.name, onCommit: commit)
}
}
// 値をリストに反映する
func commit() {
// リストから自分のIDを探してインデックス取得。
// 見つからない(たぶん親が削除した)なら、何もせず終了。
guard let index = items.firstIndex(where: { $0.id == item.id })
else { return }
// 編集内容をリスト内の商品に反映。
// indexが存在することは確認済み、out of index とは言わせないぞ
items[index].name = item.name
}
}
지워도 괜찮아졌다.
@EnvironmentObject
에 넣는 손도 있다.commit()
상당한 메소드 만들어, 아이 뷰에서는 item
통째로 건네주는 것만으로, 하면 즐겁게 commit()
를 부르는 타이밍은 요 검토.TextField
의 onCommit
는 엔터 키를 눌렀을 때라든가이므로, 조작 방법에 의해 발생하지 않는 경우도 있을지도 .onDisappear
로 확실하게 반영할 수 있는 것은? Reference
이 문제에 관하여(SwiftUI 참고 : 상위 뷰에서 목록을 삭제하면 하위 뷰가 index out of range로 떨어집니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/EmikoKishi/items/5512e6bb2ae2d0167007텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)