3

In SwiftUI on Xcode 12.1 both on iOS and macOS when dragging an object to an empty list, there's an internal crash in [UITableViewRowData numberOfRowsInSection:] () and no command line output.

Even if I try to handle the drop with .onInsert(...) on the List, it still crashes. (The onInsert closure is never called)

Here's the minimal example to reproduce:

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
        }
    }
}

What am I doing wrong?

1 Answer 1

4

Yes, by crash analyses it looks like SwiftUI defect and worth reporting feedback to Apple.

Here is possible approach to handle this scenario, which is safe and continue to work under even if/after Apple fixed the crash.

Tested with Xcode 12 / iOS 14 (List border added for demo)

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)
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.