slashlos
slashlos

Reputation: 933

Passing a class type by reference

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 ?

enter image description here

Upvotes: 0

Views: 51

Answers (2)

slashlos
slashlos

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

CRD
CRD

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

Related Questions