Swift 中的拖放 - 注册拖动类型的问题?

Posted

技术标签:

【中文标题】Swift 中的拖放 - 注册拖动类型的问题?【英文标题】:Drag and Drop in Swift - Issues with Registering for Dragged Types? 【发布时间】:2014-08-12 03:40:09 【问题描述】:

背景

我正在尝试在 Swift 中进行一些简单的拖放操作,类似于 Apple 为 Cocoa Drag and Drop 提供的示例代码。在出现错误之前,我并没有走多远。

我创建了一个 swift 类 dropView,底部有代码。 self.registered for types 似乎很有效,因为我得到了一长串图像类型或更短的列表。

当我将用于注册拖动类型的数组设置为 TIF 和 jpeg 类型时,我没有收到 draggingEntered 或 draggingUpdated 的响应。看来我错过了一些简单的东西?我将自定义视图设置为 dropView 类。

另外,当数组设置为 NSImage.imagePasteBoardTypes() 时,当我拖动文件(至少对于 TIF 和 jpeg)时,我会遇到很多错误,请参阅帖子底部的 **。

问题

为什么没有调用 draggingEntered 或 draggingUpdated?

其他问题:

我是否正确注册了拖动类型? 数组的格式是否正确? 文件顶部的 NSDraggingDestination 属性位是否在正确位置?

代码

import Cocoa

class dropView: NSView, NSDraggingDestination 

init(frame: NSRect) 
    super.init(frame: frame)
    //let theArray = [NSImage.imagePasteboardTypes()]
    let theArray = ["NSTypedFilenamesPboardType:jpg",
        "NSTypedFilenamesPboardType:JPG",
        "NSTypedFilenamesPboardType:jpeg",
        "NSTypedFilenamesPboardType:JPEG",
        "NSTypedFilenamesPboardType:jpe",
        "NSTypedFilenamesPboardType:TIF"]

    registerForDraggedTypes(theArray)
    println("INIT and REGISTER")
    println(self.registeredDraggedTypes)


override func drawRect(dirtyRect: NSRect) 
    super.drawRect(dirtyRect)

    // Drawing code here.



override func draggingEntered(sender: NSDraggingInfo!) -> NSDragOperation 
    println("Dragging Entered")
    return NSDragOperation.Copy


override func draggingUpdated(sender: NSDraggingInfo!) -> NSDragOperation  
    println("UPDATED")
    return NSDragOperation.Copy



** NSImage.imagePasteBoardTypes() 时出错

2014-06-21 11:34:38.728 DragAndDrop[96606:303] -[__NSArrayM length]: unrecognized selector sent to instance 0x610000049d80  
2014-06-21 11:34:38.729 DragAndDrop[96606:303] -[__NSArrayM length]: unrecognized selector sent to instance 0x610000049d80  
2014-06-21 11:34:38.730 DragAndDrop[96606:303] (
    0   CoreFoundation                      0x00007fff8ddaf25c __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x00007fff83a5de75 objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff8ddb212d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x00007fff8dd0d322 ___forwarding___ + 1010
    4   CoreFoundation                      0x00007fff8dd0cea8 _CF_forwarding_prep_0 + 120
    5   LaunchServices                      0x00007fff8aee1b0a XCFStringHashCaseInsensitive + 111
    6   CoreFoundation                      0x00007fff8dc6afd8 CFBasicHashFindBucket + 1032
    7   CoreFoundation                      0x00007fff8dc989c9 CFSetGetValueIfPresent + 121
    8   CoreFoundation                      0x00007fff8dc9892c -[__NSCFSet member:] + 28
    9   CoreFoundation                      0x00007fff8dccb008 -[NSSet containsObject:] + 24
    10  CoreFoundation                      0x00007fff8dd18fcf -[NSSet intersectsSet:] + 735
    11  AppKit                              0x00007fff86c645ff -[NSView(NSDrag) _hitTest:dragTypes:] + 221
    12  AppKit                              0x00007fff86c645d2 -[NSView(NSDrag) _hitTest:dragTypes:] + 176
    13  AppKit                              0x00007fff86c645d2 -[NSView(NSDrag) _hitTest:dragTypes:] + 176
    14  AppKit                              0x00007fff86c6438c -[NSWindow(NSDrag) _findDragTargetFrom:] + 111
    15  AppKit                              0x00007fff86c63280 NSCoreDragTrackingProc + 476
    16  HIServices                          0x00007fff8b8a05a3 DoEnterLeaveHandler + 389
    17  HIServices                          0x00007fff8b8a2fdd CoreDragMessageHandler + 1741
    18  CoreFoundation                      0x00007fff8dd5ace8 __CFMessagePortPerform + 760
    19  CoreFoundation                      0x00007fff8dce08d9 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
    20  CoreFoundation                      0x00007fff8dce084e __CFRunLoopDoSource1 + 478
    21  CoreFoundation                      0x00007fff8dcd1886 __CFRunLoopRun + 1830
    22  CoreFoundation                      0x00007fff8dcd0f25 CFRunLoopRunSpecific + 309
    23  HIToolbox                           0x00007fff8b908a0d RunCurrentEventLoopInMode + 226
    24  HIToolbox                           0x00007fff8b9087b7 ReceiveNextEventCommon + 479
    25  HIToolbox                           0x00007fff8b9085bc _BlockUntilNextEventMatchingListInModeWithFilter + 65
    26  AppKit                              0x00007fff8695726e _DPSNextEvent + 1434
    27  AppKit                              0x00007fff869568bb -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 122
    28  AppKit                              0x00007fff8694a9bc -[NSApplication run] + 553
    29  AppKit                              0x00007fff869357a3 NSApplicationMain + 940
    30  DragAndDrop                         0x00000001000033fd top_level_code + 109
    31  DragAndDrop                         0x000000010000343a main + 42
    32  libdyld.dylib                       0x00007fff8e1925fd start + 1
    33  ???                                 0x0000000000000003 0x0 + 3
)
2014-06-21 11:34:40.729 DragAndDrop[96606:303] -[__NSArrayM length]: unrecognized selector sent to instance 0x610000049d80
2014-06-21 11:34:40.730 DragAndDrop[96606:303] -[__NSArrayM length]: unrecognized selector sent to instance 0x610000049d80
2014-06-21 11:34:40.731 DragAndDrop[96606:303] (
    0   CoreFoundation                      0x00007fff8ddaf25c __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x00007fff83a5de75 objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff8ddb212d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x00007fff8dd0d322 ___forwarding___ + 1010
    4   CoreFoundation                      0x00007fff8dd0cea8 _CF_forwarding_prep_0 + 120
    5   LaunchServices                      0x00007fff8aee1b0a XCFStringHashCaseInsensitive + 111
    6   CoreFoundation                      0x00007fff8dc6afd8 CFBasicHashFindBucket + 1032
    7   CoreFoundation                      0x00007fff8dc989c9 CFSetGetValueIfPresent + 121
    8   CoreFoundation                      0x00007fff8dc9892c -[__NSCFSet member:] + 28
    9   CoreFoundation                      0x00007fff8dccb008 -[NSSet containsObject:] + 24
    10  CoreFoundation                      0x00007fff8dd18fcf -[NSSet intersectsSet:] + 735
    11  AppKit                              0x00007fff86c645ff -[NSView(NSDrag) _hitTest:dragTypes:] + 221
    12  AppKit                              0x00007fff86c645d2 -[NSView(NSDrag) _hitTest:dragTypes:] + 176
    13  AppKit                              0x00007fff86c645d2 -[NSView(NSDrag) _hitTest:dragTypes:] + 176
    14  AppKit                              0x00007fff86c6438c -[NSWindow(NSDrag) _findDragTargetFrom:] + 111
    15  AppKit                              0x00007fff86c63280 NSCoreDragTrackingProc + 476
    16  HIServices                          0x00007fff8b89fca4 DoTrackingMessage + 370
    17  HIServices                          0x00007fff8b8a2b36 CoreDragMessageHandler + 550
    18  CoreFoundation                      0x00007fff8dd5ace8 __CFMessagePortPerform + 760
    19  CoreFoundation                      0x00007fff8dce08d9 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
    20  CoreFoundation                      0x00007fff8dce084e __CFRunLoopDoSource1 + 478
    21  CoreFoundation                      0x00007fff8dcd1886 __CFRunLoopRun + 1830
    22  CoreFoundation                      0x00007fff8dcd0f25 CFRunLoopRunSpecific + 309
    23  HIToolbox                           0x00007fff8b908a0d RunCurrentEventLoopInMode + 226
    24  HIToolbox                           0x00007fff8b9087b7 ReceiveNextEventCommon + 479
    25  HIToolbox                           0x00007fff8b9085bc _BlockUntilNextEventMatchingListInModeWithFilter + 65
    26  AppKit                              0x00007fff8695726e _DPSNextEvent + 1434
    27  AppKit                              0x00007fff869568bb -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 122
    28  AppKit                              0x00007fff8694a9bc -[NSApplication run] + 553
    29  AppKit                              0x00007fff869357a3 NSApplicationMain + 940
    30  DragAndDrop                         0x00000001000033fd top_level_code + 109
    31  DragAndDrop                         0x000000010000343a main + 42
    32  libdyld.dylib                       0x00007fff8e1925fd start + 1
    33  ???                                 0x0000000000000003 0x0 + 3
)

【问题讨论】:

【参考方案1】:

(Swift 3、Xcode 8b6、OSX 10.11)

Apple recommends 表示不应再使用旧样式的粘贴板类型,并尽可能使用UTIs - 更好的版本是

self.register(forDraggedTypes: [kUTTypeURL as String])

这意味着您会收到来自 Finder 的拖拽,适用于所有文件类型。

由于NSImage.imagePasteboardTypes 已被弃用且没有替换,您应该在 draggingEntered 中处理过滤:

override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation 
        let pasteboard = sender.draggingPasteboard()
        let filteringOptions = [NSPasteboardURLReadingContentsConformToTypesKey:NSImage.imageTypes()]
                if pasteboard.canReadObject(forClasses: [NSURL.self], options: filteringOptions) 
                        return NSDragOperation.copy
              
        return NSDragOperation() //alternatively: []

(使用 NSPasteboardURLReadingContentsConformToTypesKey 归功于 @TroutDev 的 tutorial here)

【讨论】:

在 Xcode 9 中是registerForDraggedTypes([.URL])。另外,NSPasteboardURLReadingContentsConformToTypesKey 不见了,不知道替换的是什么。【参考方案2】:

关于崩溃

另外,当数组设置为 NSImage.imagePasteBoardTypes() 时,当我拖动文件(至少对于 TIF 和 jpeg)时,我会遇到很多错误,请参阅帖子底部的 **。

NSImage.imagePasteboardTypes() 已经返回一个数组,所以像这样使用它:

let theArray = NSImage.imagePasteboardTypes()

而不是这样

let theArray = [NSImage.imagePasteboardTypes()]

将修复崩溃。

关于 NSDragDestination

为什么没有调用 draggingEntered 或 draggingUpdated?

如果您从 Finder 中拖动,您可能需要let types = [NSFilenamesPboardType]。您拥有的代码意味着您必须自己将数据放置到粘贴板上——Finder 不会将文件内容放置到粘贴板上,而是放置文件名。

文件顶部的 NSDraggingDestination 属性位是否在正确位置?

是的! : NSDraggingDestination 告诉 Swift 你即将实现协议。

工作示例

// Public domain
import Cocoa

class DragView: NSView, NSDraggingDestination 
    init(frame: NSRect) 
        super.init(frame: frame)
        let types = [NSFilenamesPboardType]
        registerForDraggedTypes(types)
        println(self.registeredDraggedTypes)
    

    override func drawRect(dirtyRect: NSRect)  
        super.drawRect(dirtyRect)
        NSColor.whiteColor().set()
        NSRectFill(dirtyRect)
    

    override func draggingEntered(sender: NSDraggingInfo!) -> NSDragOperation  
        println("hello")
        return NSDragOperation.Copy
    

【讨论】:

感谢您的详细解答。当我从这个例子开始时,Cocoa Drag and Drop,所以如果我阅读 NSPasteboard 类文档,objective-C 代码适用于 [self registerForDraggedTypes:[NSImage imagePasteboardTypes]];已在 10.10 中弃用?

以上是关于Swift 中的拖放 - 注册拖动类型的问题?的主要内容,如果未能解决你的问题,请参考以下文章

可拖动 div 内的图像在拖动时停止了我的拖放

如何使用angularJS突出显示可拖动元素下的拖放区?

我如何使用 CGAffineTransform 进行正确的拖放

jQuery - 可拖动克隆上的拖放视觉反馈

jQuery拖放 - 检查droppable之外的拖放

带手柄的拖放