macOS SwiftUI应用含Image的View中TextField输入卡顿求助
macOS SwiftUI应用TextField输入卡顿问题
我们的macOS SwiftUI应用存在以下问题:当在包含Image组件的视图内操作TextField时,输入会出现卡顿——快速输入字符时,TextField的显示会滞后于用户的键入动作。
我们已经调试了代码,并用Instruments工具进行了性能分析,但仍未定位到卡顿的根源。
应用结构
- 顶层
ContentView展示人员列表 - 点击列表中的人员,进入
EditPersonView,该视图显示人员姓名(TextField组件)以及3张从照片库选择的图片 - 卡顿仅发生在快速输入TextField的场景下
图片处理逻辑
图片数据存储在SwiftData中,我们在.onAppear生命周期方法中加载图片数据并转换为Image数组存入内存,目的是避免视图重绘时重复加载图片。
完整代码
Person模型
import SwiftUI import SwiftData @Model class Person { var name: String @Attribute(.externalStorage) var photos: [Data] = [] init(name: String, emailAddress: String, details: String, metAt: Event? = nil) { self.name = name } }
ContentView
import SwiftUI import SwiftData struct ContentView: View { @State private var path = NavigationPath() @Environment(\.modelContext) var modelContext @State private var searchText = "" @State private var sortOrder = [SortDescriptor(\Person.name)] @Query var people: [Person] var body: some View { NavigationStack { List { ForEach(people) { person in NavigationLink(value: person) { Text(person.name) } } } .navigationDestination(for: Person.self) { person in EditPersonView(person: person, navigationPath: $path) } } } func addPerson() { let person = Person(name: "New Person", emailAddress:"", details: "") modelContext.insert(person) path.append(person) } } #Preview { ContentView() }
EditPersonView
import PhotosUI import SwiftData import SwiftUI struct EditPersonView: View { @Bindable var person: Person @Binding var navigationPath: NavigationPath @State private var pickerItems = [PhotosPickerItem]() @State private var selectedImages = [Image]() var body: some View { VStack { ScrollView(.horizontal, showsIndicators: true) { HStack(spacing: 8) { ForEach(0..<selectedImages.count, id: \.self) { index in selectedImages[index] .resizable() .scaledToFit() } } } HStack { PhotosPicker("Select images", selection: $pickerItems, matching: .images, photoLibrary: .shared()) Button("Remove photos") { person.photos.removeAll() selectedImages.removeAll() pickerItems.removeAll() } } TextField("Name", text: $person.name) .textContentType(.name) } .navigationTitle("Edit Person") .navigationDestination(for: Event.self) { event in //show some info about the event. unrelated to issue } .onChange(of: pickerItems, addImages) .padding() .onAppear { person.photos.forEach { photoData in let nsImage = NSImage(data: photoData) let image = Image(nsImage: nsImage!) selectedImages.append(image) } } } func addImages() { Task { selectedImages.removeAll() for item in pickerItems { if let loadedImageData = try await item.loadTransferable(type: Data.self) { person.photos.append(loadedImageData) let nsImage = NSImage(data: loadedImageData) let image = Image(nsImage: nsImage!) selectedImages.append(image) } } } } } #Preview { do { let previewer = try Previewer() return EditPersonView( person: previewer.person, navigationPath: .constant(NavigationPath()) ) .modelContainer(previewer.container) } catch { return Text("Failed to create preview: \(error.localizedDescription)") } }
Previewer
import Foundation import SwiftData import SwiftUICore @MainActor struct Previewer { let container: ModelContainer let event: Event let person: Person let ship: Image init() throws { let config = ModelConfiguration(isStoredInMemoryOnly: true) container = try ModelContainer(for: Person.self, configurations: config) event = Event(name: "Preview Event", location: "Preview Location") person = Person(name: "Preview Name", emailAddress: "preview@preview.com", details: "", metAt: event) ship = Image("Enterprise") //any image for the preview container.mainContext.insert(person) } }
主入口
import SwiftUI import SwiftData @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } .modelContainer(for: Person.self) } }
卡顿现象示例
快速输入时,最后键入的字符会延迟约1秒才显示在TextField中。
环境信息
该问题在以下设备和系统版本中均可复现:
- Mac Studio M1 Max
- iMac M4
- MacBook Pro M1 Pro
- 系统版本:Sequoia 15.3.2
- XCode版本:16.2
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

