首页 > 解决方案 > 清理画布时拖放新的 UILables 时出现错误,如何解决?

问题描述

我有一个名为“TestDraw”的视图,我可以在其中从 collectionView 拖放 UILables。在“TestDraw”上,也允许自由绘图。我还设置了 BarItems 来清除画布。但是,例如,如果我拖放两个标签并画一条线然后点击清除,当我再次尝试拖放时,应用程序崩溃。

我正在使用 Xcode 10.2、Swift 4.2。崩溃时的控制台输出是:

2019-04-07 12:52:24.346501+0800 TrailingTest[497:23125599]-[OS_dispatch_group convertPoint:fromLayer:]:无法识别的选择器发送到实例 0x6000011b13b0
2019-04-07 12:52:24.389911+0800 TrailingTest[497:23125599] *** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[OS_dispatch_group convertPoint:fromLayer:]:无法识别的选择器发送到实例 0x6000011b13b0”
*** 首先抛出调用堆栈:
(
    0 核心基础 0x000000010e4786fb __exceptionPreprocess + 331
    1 libobjc.A.dylib 0x000000010da1cac5 objc_exception_throw + 48
    2核心基础0x000000010e496ab4-[NSObject(NSObject)不识别选择器:]+132
    3 核心基础 0x000000010e47d443 ___forwarding___ + 1443
    4 核心基础 0x000000010e47f238 _CF_forwarding_prep_0 + 120
    5 UIKitCore 0x0000000117b984e7 -[UIView(几何)转换点:从视图:] + 102
    6 UIKitCore 0x0000000117b98126 __38-[UIView(几何) hitTest:withEvent:]_block_invoke + 102
    7 核心基础 0x000000010e3a4013 -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 483
    8 UIKitCore 0x0000000117b97ce8 -[UIView(几何) hitTest:withEvent:] + 460
    9 UIKitCore 0x0000000117b981ea-[UIView(几何)_hitTest:withEvent:windowServerHitTestWindow:] + 87
    10 UIKitCore 0x0000000117b98139 __38-[UIView(几何) hitTest:withEvent:]_block_invoke + 121
    11 核心基础 0x000000010e3a4013 -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 483
    12 UIKitCore 0x0000000117b97ce8 -[UIView(几何) hitTest:withEvent:] + 460
    13 UIKitCore 0x0000000117b981ea -[UIView(几何)_hitTest:withEvent:windowServerHitTestWindow:] + 87
    14 UIKitCore 0x0000000117b98139 __38-[UIView(几何) hitTest:withEvent:]_block_invoke + 121
    15 核心基础 0x000000010e3a4013 -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 483
    16 UIKitCore 0x0000000117b97ce8 -[UIView(几何) hitTest:withEvent:] + 460
    17 UIKitCore 0x0000000117b981ea-[UIView(几何)_hitTest:withEvent:windowServerHitTestWindow:] + 87
    18 UIKitCore 0x0000000117b98139 __38-[UIView(几何) hitTest:withEvent:]_block_invoke + 121
    19 核心基础 0x000000010e3a4013 -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 483
    20 UIKitCore 0x0000000117b97ce8 -[UIView(几何) hitTest:withEvent:] + 460
    21 UIKitCore 0x0000000117b981ea -[UIView(几何)_hitTest:withEvent:windowServerHitTestWindow:] + 87
    22 UIKitCore 0x0000000117b98139 __38-[UIView(几何) hitTest:withEvent:]_block_invoke + 121
    23 核心基础 0x000000010e3a4013 -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 483
    24 UIKitCore 0x0000000117b97ce8 -[UIView(几何) hitTest:withEvent:] + 460
    25 UIKitCore 0x0000000117b981ea-[UIView(几何)_hitTest:withEvent:windowServerHitTestWindow:] + 87
    26 UIKitCore 0x0000000117b98139 __38-[UIView(几何) hitTest:withEvent:]_block_invoke + 121
    27 核心基础 0x000000010e3a4013 -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 483
    28 UIKitCore 0x0000000117b97ce8 -[UIView(几何) hitTest:withEvent:] + 460
    29 UIKitCore 0x0000000117b74223 -[UITransitionView hitTest:withEvent:] + 44
    30 UIKitCore 0x0000000117b981ea -[UIView(几何)_hitTest:withEvent:windowServerHitTestWindow:] + 87
    31 UIKitCore 0x0000000117b98139 __38-[UIView(几何) hitTest:withEvent:]_block_invoke + 121
    32 核心基础 0x000000010e3a4013 -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 483
    33 UIKitCore 0x0000000117b97ce8 -[UIView(几何) hitTest:withEvent:] + 460
    34 UIKitCore 0x0000000117b981ea -[UIView(几何)_hitTest:withEvent:windowServerHitTestWindow:] + 87
    35 UIKitCore 0x00000001177346bc-[UIWindow_hitTestLocation:inScene:withWindowServerHitTestWindow:event:] + 194
    36 UIKitCore 0x0000000117734455 __70+[UIWindow _hitTestToPoint:forEvent:windowServerHitTestWindow:screen:]_block_invoke + 159
    37 UIKitCore 0x0000000117734157 +[UIWindow _topVisibleWindowPassingTest:] + 506
    38 UIKitCore 0x0000000117734358 +[UIWindow_hitTestToPoint:forEvent:windowServerHitTestWindow:screen:] + 245
    39 UIKitCore 0x0000000117734571 +[UIWindow _globalHitTestForLocation:inWindowServerHitTestWindow:withEvent:] + 223
    40 UIKitCore 0x00000001177c9424-[_UIDragEventSample hitTestWithEvent:constrainToWindowServerHitTestContext:] + 250
    41 UIKitCore 0x00000001177ca325-[UIDragEvent _updateGesturesFromCurrentSample] + 202
    42 UIKitCore 0x00000001177ca171-[UIDragEvent _updateFromCurrentSample] + 649
    43 UIKitCore 0x00000001177ca217 -[UIDragEvent _sendIfNeeded] + 72
    44 UIKitCore 0x00000001171dd4ca __48-[_UIInternalDraggingSessionDestination 连接]_block_invoke + 1010
    45 UIKitCore 0x00000001171e2da9 __59-[_UIDruidDestinationConnection initWithSessionIdentifier:]_block_invoke.1547 + 679
    46 libdispatch.dylib 0x0000000110ac2db5 _dispatch_client_callout + 8
    47 libdispatch.dylib 0x0000000110ac62ba _dispatch_block_invoke_direct + 300
    48 前板服务 0x0000000119750146 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 30
    49 前板服务 0x000000011974fdfe -[FBSSerialQueue _performNext] + 451
    50 前板服务 0x0000000119750393 -[FBSSerialQueue _performNextFromRunLoopSource] + 42
    51 核心基础 0x000000010e3dfbe1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    52 核心基础 0x000000010e3df463 __CFRunLoopDoSources0 + 243
    53 核心基础 0x000000010e3d9b1f __CFRunLoopRun + 1231
    54 核心基础 0x000000010e3d9302 CFRunLoopRunSpecific + 626
    55 图形服务 0x0000000113bc62fe GSEventRunModal + 65
    56 UIKitCore 0x00000001176e7ba2 UIApplicationMain + 140
    57 尾随测试 0x000000010d0f1c0b 主要 + 75
    58 libdyld.dylib 0x0000000110b37541 开始 + 1
    59 ???0x0000000000000001 0x0 + 1
)
libc++abi.dylib:以 NSException 类型的未捕获异常终止

这是清除画布的功能以及调用位置:

 func ClearCanvas () {
    path.removeAllPoints()
    self.layer.sublayers = nil
    self.setNeedsDisplay()
}

@IBAction func clear(_ sender: UIBarButtonItem) {
    if TestDraw.path != nil{    
        TestDraw.ClearCanvas()
    }
}

如果有人能帮助我解决这个问题,或者至少提供一些可能对我有帮助的线索和调试技巧,我将非常感激。非常感谢!

下面是实现collectionView的代码:

class DocumentViewController: UIViewController,UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDragDelegate, UICollectionViewDropDelegate {
var numbersChoices = ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20"]
var numberOfCorrectMatches = 0
private var font: UIFont {
    return UIFontMetrics(forTextStyle: .body).scaledFont(for: UIFont.preferredFont(forTextStyle: .body).withSize(60.0))
}
private var numberCardsSet: NumberCardsSet?{
    get{
        let cards = TestDraw.subviews.compactMap{$0 as? UILabel}.compactMap{NumberCardsSet.CardInfo(label: $0)} 
        return NumberCardsSet(numberCards: cards)
    }
    set{
        TestDraw.subviews.compactMap{$0 as? UILabel}.forEach{$0.removeFromSuperview()}
    }
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return numbersChoices.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "numberCell", for: indexPath)
    if let numberCell = cell as? numberCollectionViewCell{
        let text = NSAttributedString(string: numbersChoices[indexPath.item], attributes: [.font:font])
        numberCell.label.attributedText = text
    }
    return cell
}

func collectionView(_ collectionView: UICollectionView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem] {
    return dragItems(at: indexPath)
}

func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
    session.localContext = collectionView
    return dragItems(at: indexPath)
}
func collectionView(_ collectionView: UICollectionView, canHandle session: UIDropSession) -> Bool {
    return session.canLoadObjects(ofClass: NSAttributedString.self)
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
    let isSelf = (session.localDragSession?.localContext as? UICollectionView) == collectionView
    return UICollectionViewDropProposal(operation: isSelf ? .move: .copy, intent: .insertAtDestinationIndexPath)
}
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
    let destinationIndexPath = coordinator.destinationIndexPath ?? IndexPath(item: 0, section: 0)
    for item in coordinator.items {
        if let sourceIndexPath = item.sourceIndexPath{
            if let attributedString = item.dragItem.localObject as? NSAttributedString{
                collectionView.performBatchUpdates({numbersChoices.remove(at: sourceIndexPath.item)
                    numbersChoices.insert(attributedString.string, at: destinationIndexPath.item)
                    collectionView.deleteItems(at: [sourceIndexPath])
                    collectionView.insertItems(at: [destinationIndexPath])})
            }
            coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
        }else{
            let placeholderContext = coordinator.drop(item.dragItem, to: UICollectionViewDropPlaceholder(insertionIndexPath: destinationIndexPath, reuseIdentifier: "DropPlaceholderCell"))
            item.dragItem.itemProvider.loadObject(ofClass: NSAttributedString.self){(provider, error) in DispatchQueue.main.sync {
                if let attributedString = provider as? NSAttributedString{
                    placeholderContext.commitInsertion(dataSourceUpdates: {insertionIndexPath in
                        self.numbersChoices.insert(attributedString.string, at: insertionIndexPath.item)
                    })
                }else {
                    placeholderContext.deletePlaceholder()
                }
                }
            }
        }
    }
}
private func dragItems (at indexPath: IndexPath) -> [UIDragItem]{
    if let attributedString = (numberCollectionView.cellForItem(at: indexPath) as? numberCollectionViewCell)?.label.attributedText{
        let dragItem = UIDragItem(itemProvider: NSItemProvider(object: attributedString))
        dragItem.localObject = attributedString
        return [dragItem]
    }else {
        return []
    }
}
...
}

这是在画布上实现拖放的代码:

class TrailingCanvas: UIView,UIDropInteractionDelegate {
var UserMatchingLocation = [CGFloat]()
var UILabelLocation = [CGFloat]()
 required init?(coder aDecoder: NSCoder) {
    super.init(coder:aDecoder)
    setup()
}
private func setup() {
    addInteraction(UIDropInteraction(delegate: self))
}
func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
    return session.canLoadObjects(ofClass: NSAttributedString.self)
}
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
    return UIDropProposal(operation: .copy)
}
func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
    session.loadObjects(ofClass: NSAttributedString.self){
        providers in
        let dropPoint = session.location(in: self)
        for attributedString in providers as? [NSAttributedString] ?? []{
            self.addLabel(with: attributedString, centeredAt: dropPoint)
        }
    }
}
private func addLabel (with attributedString:NSAttributedString, centeredAt point: CGPoint){
    let label = UILabel()
    label.backgroundColor = .clear
    label.attributedText = attributedString
    label.sizeToFit()
    label.center = point
    addSubview(label)
    UILabelLocation.append(point.x)
    print(point.x)
}
...
}

这是主故事板的屏幕截图。 主线故事板

我还在 Github 上创建了一个 repo。这是链接:https ://github.com/Feanor007/TrailingTest-repo

标签: iosswiftdrag-and-dropdrawingunrecognized-selector

解决方案


推荐阅读