SwiftUI:列表之间的拖放有时会崩溃

时间:2020-07-03 08:12:02

标签: swiftui

我正在使用Xcode 12 beta,并试图创建一个视图,在该视图中可以将左侧列表中的项目拖到右侧列表中并放到那里。

在以下情况下会崩溃:

  • 列表为空。
  • 列表不为空,但是在将项目首先拖动到其他列表元素之后,该项目被拖动到最后一个列表元素的后面。在拖动该项目时已经出现崩溃,而不是在拖放该项目时(即尚未调用.onInsert)。

崩溃消息告诉:

SwiftUI的通用专业化(在Swift中的扩展名):Swift.RandomAccessCollection <其中A.Index:Swift.Strideable,A.Indices == Swift.Range ,A。 Index.Stride == Swift.Int> .index(之后:A.Index)-> A.Index:

有什么想法为什么会发生以及如何避免?

左侧列表代码:

struct AvailableBuildingBricksView: View {

    @StateObject var buildingBricksProvider: BuildingBricksProvider = BuildingBricksProvider()
    
    var body: some View {

        List {

            ForEach(buildingBricksProvider.availableBuildingBricks) { buildingBrickItem in
                
                Text(buildingBrickItem.title)
                    .onDrag {
    
                        self.provider(buildingBrickItem: buildingBrickItem)
                    }
            }
        }
    }
    
    private func provider(buildingBrickItem: BuildingBrickItem) -> NSItemProvider {

        let image = UIImage(systemName: buildingBrickItem.systemImageName) ?? UIImage()
        let provider = NSItemProvider(object: image)
        
        provider.suggestedName = buildingBrickItem.title

        return provider
    }
}

final class BuildingBricksProvider: ObservableObject {
    
    @Published var availableBuildingBricks: [BuildingBrickItem] = []
    
    init() {

        self.availableBuildingBricks = [
            TopBrick.personalData,
            TopBrick.education,
            TopBrick.work,
            TopBrick.overviews
        ].map({ return BuildingBrickItem(title: $0.title,
                                         systemImageName: "stop") })
    }
}

struct BuildingBrickItem: Identifiable {
    
    var id: UUID = UUID()

    var title: String
    var systemImageName: String
}

正确的列表代码:

struct DocumentStructureView: View {
    
    @StateObject var documentStructureProvider: DocumentStructureProvider = DocumentStructureProvider()
    
    var body: some View {

        List {
            
            ForEach(documentStructureProvider.documentSections) { section in
                
                Text(section.title)
            }
            .onInsert(of: ["public.image"]) {
                
                self.insertSection(position: $0,
                                 itemProviders: $1,
                                 top: true)
            }
        }
    }

    func insertSection(position: Int, itemProviders: [NSItemProvider], top: Bool) {
        
        for item in itemProviders.reversed() {
            
            item.loadObject(ofClass: UIImage.self) { image, _ in
                
                if let _ = image as? UIImage {
                    
                    DispatchQueue.main.async {
                        
                        let section = DocumentSectionItem(title: item.suggestedName ?? "Unknown")
                        self.documentStructureProvider.insert(section: section, at: position)
                    }
                }
            }
        }
    }
}

final class DocumentStructureProvider: ObservableObject {
    
    @Published var documentSections: [DocumentSectionItem] = []
    
    init() {
        
        documentSections = [
            DocumentSectionItem(title: "Dummy")
        ]
    }
    
    func insert(section: DocumentSectionItem, at position: Int) {
        
        if documentSections.count == 0 {
            
            documentSections.append(section)
            return
        }
        
        documentSections.insert(section, at: position)
    }
}

struct DocumentSectionItem: Identifiable {
    
    var id: UUID = UUID()
    var title: String
}

1 个答案:

答案 0 :(得分:0)

好吧,我成功地使问题可重现,代码如下。

复制步骤:

  1. 将“ 1”上的“ A”拖动为右侧的第一项。
  2. 在“ 1”上拖动另一个“ A”,将其拖动,然后在“ 5”->崩溃后将其慢慢拉下。

崩溃前未调用drop函数。

struct ContentView: View {
    var body: some View {
        HStack {
            LeftList()
            Divider()
            RightList()
        }
    }
}

import SwiftUI
import UniformTypeIdentifiers

struct LeftList: View {
    
    var list: [String] = ["A", "B", "C", "D", "E"]
    
    var body: some View {
        List(list) { item in
            Text(item)
                .onDrag {
                    
                    let stringItemProvider = NSItemProvider(object: item as NSString)
                    return stringItemProvider
                }
        }
    }
}

import SwiftUI
import UniformTypeIdentifiers

struct RightList: View {
    @State var list: [String] = ["1", "2", "3", "4", "5"]
    
    var body: some View {
        List {
            
            ForEach(list) { item in
                Text(item)
            }
            .onInsert(
                of: [UTType.text],
                perform: drop)
        }
    }

    private func drop(at index: Int, _ items: [NSItemProvider]) {

        debugPrint(index)
        
        for item in items {

            _ = item.loadObject(ofClass: NSString.self) { text, _ in

                debugPrint(text)

                DispatchQueue.main.async {
                    
                    debugPrint("dispatch")
                    
                    text.map { self.list.insert($0 as! String, at: index) }
                }
            }
        }
    }
}