SwiftUI:拖入空白列表时崩溃

时间:2020-10-30 16:13:25

标签: swift swiftui-list swiftui

在iOS和macOS上的Xcode 12.1上的SwiftUI中,将对象拖到空白列表时,[UITableViewRowData numberOfRowsInSection:] ()中发生内部崩溃,并且没有命令行输出。

即使我尝试使用列表上的.onInsert(...)处理放置,它仍然崩溃。 (永远不会调用onInsert闭包)

这是复制的最小示例:

struct ContentView: View {
    let string = "Hello World"
    
    var body: some View {
        HStack {
            Text(string) // Object to drag
                .onDrag({NSItemProvider(object: string as NSString)})
            
            List {} // When dragging object onto here, there's a crash
        }
    }
}

我在做什么错了?

1 个答案:

答案 0 :(得分:2)

是的,通过崩溃分析,它看起来像是SwiftUI缺陷,值得向Apple报告反馈。

这里是处理这种情况的一种可能的方法,这种方法是安全的,即使/在Apple修复崩溃之后,也可以继续使用。

在Xcode 12 / iOS 14上进行了测试(为演示添加了列表边框)

demo

import SwiftUI
import UniformTypeIdentifiers

struct ContentView: View {
    let string = "Hello World"
    @State private var items: [String] = []

    // border with highlight added just for better visibility
    @State private var dragOver = false
    
    var body: some View {
        HStack {
            Text(string) // Object to drag
                .onDrag({NSItemProvider(object: string as NSString)})
            
            List {
                ForEach(items, id: \.self) {
                    Text($0)
                }
                .onInsert(of: [.text]) { index, providers in
                    self.handle(providers: providers, index: index)
                }
            }
            .overlay(helperOverlay()) // << helper to handle empty list
            .border(dragOver ? Color.red : Color.green, width: 4) // << just for demo
        }
    }
    
    private func helperOverlay() -> some View {
        Group {
            if items.isEmpty {
                Color.white.opacity(0.0001)  // << should be something opaque
                    .onDrop(of: [.text], isTargeted: $dragOver) { providers -> Bool in
                        self.handle(providers: providers)
                        return true
                    }
            }
        }
    }
    
    private func handle(providers: [NSItemProvider], index: Int? = nil) {
        guard let provider = providers.first else { return }
        provider.loadDataRepresentation(forTypeIdentifier: "public.text") { (data, _) in
            guard let data = data, let value = String(data: data, encoding: .utf8) else { return }
            if let index = index {
                items.insert(value, at: index)
            } else {
                items.append(value)
            }
        }
    }
}