Drag and Drop without any bells and whistles

Apple dedicated four sessions in the WWDC 2017 to its new drag and drop methods, which I am going to assume is a reflection of how much they put into them and want you to get out of ‘em. I watched all the sessions but was disappointed when I discovered the code presented in session 227 with Dave Rahardja and Tanu Singhal had already out lived its useful life, failing to even compile. My inner code monkey took charge and I logged a call with Apple that weekend. I watched 227 again the following Monday and googled tutorials on the subject to see if could find some working code, but nothing turned up.

Most of the tutorials you find online if not all seem focus on the subject covered in the introduction to drag and drop, transferring images and/or strings with convenience methods. I wanted to do more. I wanted to create a truly custom drag and drop to work within my app, not with others. It was no use I needed to understand how to setup NSItemProviderReading and NSItemProviderWriting protocols. I couldn’t wait for Apple.

I returned to the video a third time and started to rewrite the code. To begin with I created a class of my own, calling it CustomClass [not very original I know] adding to it the required protocol and methods.

class CustomClass: NSObject, NSItemProviderWriting, NSItemProviderReading {

var image2D:Data!

static var readableTypeIdentifiersForItemProvider = [kUTTypeData as String]

static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self {
return try self.init(itemProviderData: data, typeidentifier: kUTTypeData as String)
}

required init(itemProviderData data: Data, typeidentifier: String) throws {
super.init()
image2D = data
}
static var writableTypeIdentifiersForItemProvider = [kUTTypeData as String] func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void) -> Progress? {
let data2E = image2D
completionHandler(data2E, nil)
return nil
}
}

The key it seems is universal type identifier or UTI for nerds. For this, I choose data, the variable image2D you see here. Ok if you watch 227 Mr Rahardja he does say, you should shy away from generic types if you want to make your app as compatible as possible. But wait my goal wasn’t to build in drag and drop into an app that would play with everyone else; my goal was to build custom drag and drop that would only need to play with itself. And data was the perfect choice, with it implemented I could literally drag and drop anything and everything!!

Once I had my custom class, all I needed to do was implement it in my drop and drag calls. The drag looks like this. This was harder to figure ironically than the missing code in the custom class.

func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
let image2V = interaction.view as! UIImageView
let data:Data = UIImageJPEGRepresentation(image2V.image!, 1.0)!
var item2P:CustomClass!
do {
item2P = try CustomClass(itemProviderData: data, typeidentifier: kUTTypeData as String)
} catch {
print(“foo bar”)
}

let itemProvider = NSItemProvider(object: item2P )
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = UIImage(data: data)
return [dragItem]
}

And in drop like this…

func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
if session.canLoadObjects(ofClass: CustomClass.self) {
session.loadObjects(ofClass: CustomClass.self) { imageItems in
let images2D = imageItems as! [CustomClass]
let image1D = images2D.first
let image2S = UIImage(data: (image1D?.image2D)!)
DispatchQueue.main.async {
(interaction.view as! UIImageView).image = image2S
}
}
}
}

Of course, you need to have add your drops and drags to your customClass objects, in your viewController too as well as add the protocol to the principle VC class, but that I am guessing you already know.

 let dragInteraction = UIDragInteraction(delegate: self)
imageView.addInteraction(dragInteraction)

let dropInteraction = UIDropInteraction(delegate: self)
imageView2.addInteraction(dropInteraction)

Which in fact is all you need to know to build your own custom class drag and drop methods into your app believe it or not. Yes, if your wondering, your right my custom class objects are just images. But wait there is a means to my madness. I wanted to keep my demo code as simple as possible with next to no bells and whistles so that I and you could build on it without having to think too hard the next time.

Coding for 35+ years, enjoying using and learning Swift/iOS development. Writer @ Better Programming, @The StartUp, @Mac O’Clock, Level Up Coding & More

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store