Reputation: 933
So I want I my base tableView, upon which I've derived others, to centralize drag-n-drop operations. Each of these tableViews have a distinct array controller as its dataSource, with each item class conforming to pasteboard reading and writing protocols.
But I'm stuck on its setup
override func mouseDragged(with event: NSEvent) {
let arrayController = self.dataSource as! NSArrayController
let itemClass = arrayController.objectClass
let objects = arrayController.arrangedObjects as! [itemClass]
let indexSet = self.selectedRowIndexes
var items = [NSDraggingItem]()
for index in indexSet {
let item = NSDraggingItem.init(pasteboardWriter: objects[index])
items.append(item)
}
self.beginDraggingSession(with: items, event: event, source: self)
}
as I get an error ?
Upvotes: 0
Views: 51
Reputation: 933
I will posit my own answer with the Sweeper's suggestion and CRD's excellent commentary.
The source objects, conform to the pasteboard writing protocol - NSPasteboardWriting; I mandate it. The target casting confirms this. My issue was a noob case of thinking objC, and cast at source vs target but enforcing just the same; I hope ;-).
override func mouseDragged(with event: NSEvent) {
let arrayController = self.dataSource as! NSArrayController
let objects = arrayController.arrangedObjects as! [NSPasteboardWriting]
let delegate = self.delegate as! NSViewController
let indexSet = self.selectedRowIndexes
var items = [NSDraggingItem]()
for index in indexSet {
let dragImage = (delegate.view.window?.windowController?.document as! Document).displayImage!
let item = NSDraggingItem.init(pasteboardWriter: objects[index])
item.setDraggingFrame(self.rect(ofRow: index), contents: dragImage)
item.draggingFrame = self.rect(ofRow: index)
items.append(item)
}
self.beginDraggingSession(with: items, event: event, source: self)
}
Upvotes: 0
Reputation: 53010
Short Answer: This just isn't how Swift works, cast (as?
or as!
) to an appropriate compile time type – in this case from the use of objects
in NSDraggingItem.init(pasteboardWriter: objects[index])
that is probably [NSPasteBoardWriting]
Longer Answer:
You may have just made a simple error, we all do sometimes, and the short answer is enough. But if you are wondering why your code isn't accepted maybe this will help and hopefully not confuse!
What you are trying to do is a form of dynamic typing, you set itemClass
to a type that at compile time nothing is known about except that it is some class type.
At its core Swift is essentially a statically typed language, it works by either knowing everything about the type of something, e.g. when something is declared to have a particular reference or value type; by knowing something about the type, e.g. when something has a protocol type; or even nothing, e.g. when something is of unconstrained generic parameter type and in all these cases what can be done is largely limited by this knowledge.
Variable types are not supported; while there are less specific types, e.g. the AnyClass
in the example, operations specific to the actual runtime type of something cannot be performed until a cast to that specific (compile time known) type is made (with as?
or as!
)
Swift does support some dynamic typing features, notably in its support for parts of Objective-C – which has both statically and dynamically typed parts; but these do not give you what you are trying to do here, that is cast to a type unknown until runtime.
You probably know Objective-C, a simple example of how the two languages differ in static/dynamic approach is what happens when a method/function is called. For Objective-C method dispatch is dynamic, the compiled code performs a search for the implementation of the method and that search may fail resulting in a runtime error and abort. In Swift (excluding its interworking with Objective-C) when a function is called the compiled code does not search, the implementation is known to exist at compile time and there can by no runtime error and abort.
To do what you are attempting you need to determine at design time what type you need to perform the desired operation (construct an NSDraggingItem
in this case) and whether you either absolutely know or maybe know the value you have will at runtime conform to that type. If you absolutely know you can use the as!
cast, which will abort execution if you are wrong, or you can use the as?
which allows you to test for success and take appropriate action if you have something of unplanned type.
HTH
Upvotes: 1