Drag and Drop - создайте NSItemProvider из моей модели

Пойдем по частям!

Я пытаюсь реализовать Drag and Drop в моем UICollectionViewController,

Источник данных для UICollectionView является array обычая Model Struct Я создал

По мере необходимости я установил свой collectionView.dragDelegate = self и тем самым я реализовал required protocol functionitemsForBeginning session: UIDragSession...

Вот где начинается моя проблема:

struct Model {
    // some variables
    // Some initializations
}

var myModelDatasource: [Model] = [model1, model2, model3, ...] // it's a simple case example

func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
    let item = myModelDatasource[indexPath.row]

    let itemProvider = NSItemProvider(object: item)
    let dragItem = UIDragItem(itemProvider: itemProvider) // <-- ERROR HERE, Even If i force cast as NSItemProviderWriting
    dragItem.localObject = item

    return [dragItem]
}

Я не могу создать dragItem из-за моей модели не соответствует типу NSItemProviderWriting,

Если я заставлю источник данных иметь тип String и бросить предмет в NSString это работает, но не с моим struct Model,

Кто-нибудь знает, как решить эту проблему?

2 ответа

Решение

Вы должны использовать class (не структура) для вашего Modelпотому что, как вы предложили, вы должны соответствовать NSItemProviderWriting (который наследует от NSObjectProtocol):

Протокол, который вы реализуете в классе, чтобы позволить провайдеру элемента получать данные из экземпляра класса.

Многие API ожидают подклассы NSObjectследовательно, вы должны использовать класс, Apple, блог: структура против класса

Так что ваши Model должно быть что-то вроде:

class Model : NSObject, NSItemProviderWriting {
    public static var writableTypeIdentifiersForItemProvider: [String] {
        return [] // something here
    }

    public func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Swift.Void) -> Progress? {
        return nil // something here
    }
}

Вот полный пример, который я реализовал

1- модельный класс / структура

2- вызов метода настройки в viewDidload

3- реализовать протоколы просмотра коллекции перетаскиванием

      class ImageRequestModel {
    var uuid = UUID().uuidString
    var filename: String?
    var url: String? // displayable
    var caption:String?
    var image: UIImage? // its mean new or modifiable
  
}

 func setupCollectionView(){
        self.collectionView?.registerCell(id: PhotoCVC.className)
        self.collectionView?.collectionViewLayout = UICollectionViewLayout.createTwoColumnLayout()
        self.collectionView?.dataSource = self
        self.collectionView?.delegate = self
        self.collectionView?.dragInteractionEnabled = true
        self.collectionView?.dragDelegate = self
        self.collectionView?.dropDelegate = self
        self.setupRefreshControl()
    
    }


extension InspectionPhotosView: UICollectionViewDropDelegate {


    func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
        var destinationIndexPath: IndexPath
        if let indexpath = coordinator.destinationIndexPath {
            destinationIndexPath = indexpath
        } else {
            guard let row = self.collectionView?.numberOfItems(inSection: 0) else { return }
            destinationIndexPath = IndexPath(item: row - 1, section: 0)
        }
        if coordinator.proposal.operation == .move {
            Logger.debug(message: "\(destinationIndexPath.row)")
            self.reorderItems(coordinater: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
        }
    }


    func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
//      if session.localDragSession != nil {
//        return UICollectionViewDropProposal(operation: .forbidden)
//      } else {
//        return UICollectionViewDropProposal(
//          operation: .copy,
//          intent: .insertAtDestinationIndexPath)
//      }

        if collectionView.hasActiveDrag {
            return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
        }
        return UICollectionViewDropProposal(operation: .forbidden)
    }

    fileprivate func reorderItems(coordinater: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) {
        if let item = coordinater.items.first, let sourceIndexPath = item.sourceIndexPath {
            collectionView.performBatchUpdates ({


                let object = imageList.remove(at: sourceIndexPath.item)
               // object.order = destinationIndexPath.row
                self.imageList.insert(object, at: destinationIndexPath.item)
                self.updateCollectionView(imageList)
                self.addPhotoView?.isImageSelected = true

                collectionView.deleteItems(at: [sourceIndexPath])
                collectionView.insertItems(at: [destinationIndexPath])


            }, completion: nil)

        }
    }
}



extension InspectionPhotosView: UICollectionViewDragDelegate {
    func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
        let item = self.imageList[indexPath.row]
        let itemProvider = NSItemProvider(object: item.uuid as NSString)
        let dragItem = UIDragItem(itemProvider: itemProvider)
           return [dragItem]

    }
}
Другие вопросы по тегам