SwiftUI:iPad横屏模式下NavigationSplitView在iOS16.2崩溃
这个崩溃是iOS 16.2 SwiftUI的已知bug,根源在于切换成员时,中间列的List会复用之前的实例,导致内部选择状态没有完全重置——当你从元素多的书单切换到元素少的书单时,之前选中最后一个元素的残留状态会触发内部断点。
修复方法
给中间列的List添加一个基于memberID的id修饰符,确保切换成员时List会被重新创建,彻底清空旧的选择状态:
List(books.filter({ $0.memberId == memberID }), selection: $bookID) { book in Text(book.name) } .id(memberID) // 新增这一行
完整修改后的代码
// // ContentView.swift // test // import SwiftUI struct Member: Hashable, Identifiable { var id: Int var name: String } struct Book: Hashable, Identifiable { var id: Int var memberId: Int var name: String } struct ContentView: View { @State private var memberID: Member.ID? @State private var bookID: Book.ID? @State private var columnVisibility = NavigationSplitViewVisibility.all var members = [ Member(id:1, name:"George"), Member(id:2, name:"John"), Member(id:3, name:"Luca"), ] var books = [ Book(id:1,memberId:1, name:"A good Book"), Book(id:2, memberId:1, name:"Another great Book"), Book(id:3, memberId: 1, name:"Very good Book"), Book(id:4,memberId:1, name:"Lame Book"), Book(id:5, memberId:1, name:"Big Book"), Book(id:6, memberId: 2, name:"Small Book"), Book(id:7,memberId:2, name:"Green Book"), Book(id:8, memberId:2, name:"Yellow Book"), Book(id:9, memberId: 3, name:"Boring Book"), Book(id:10, memberId: 3, name:"Best Book"), ] var body: some View { NavigationSplitView(columnVisibility: $columnVisibility) { List(members, selection: $memberID) { member in HStack{ Text("ID: \(member.id)") Text("Name: \(member.name)") } } } content: { if memberID == nil { Text("select") } else { List(books.filter({ $0.memberId == memberID }), selection: $bookID) { book in Text(book.name) } .id(memberID) // 新增的id修饰符 } } detail: { Text("Details") } .onChange(of: memberID){ _ in bookID = nil } } }
为什么这个方法有效
虽然你已经在onChange里把bookID设为nil,但SwiftUI的List内部还会维护一些私有状态(比如滚动位置、选中索引的缓存)。当切换到元素更少的列表时,这些旧状态会导致内部逻辑出错。通过给List绑定memberID作为唯一标识,每次切换成员时SwiftUI都会销毁旧List并创建新实例,彻底清除所有旧状态,从而避免崩溃。
这个问题在iOS 16.3及以上版本已经被苹果修复,如果你能升级部署目标版本,也可以通过系统更新解决。
内容的提问来源于stack exchange,提问作者KalleBl0mquist
相关产品推荐
相关产品推荐

