gpt4 book ai didi

ios - 手势识别器应该开始 : Unrecognized selector sent to instance

转载 作者:行者123 更新时间:2023-11-30 14:06:35 26 4
gpt4 key购买 nike

出于完全不同的目的,我正在基于 nghialv ( https://github.com/nghialv/Sapporo ) 的札幌实现带有日历的 Collection View 。我想定义将在 10 秒帧中通过六个不同 channel 发送的脉冲。因此,我有一个秒与 channel 的 PulseCollectionView。

我想使用本教程实现长按后单元格拖动:http://karmadust.com/drag-and-rearrange-uicollectionviews-through-layouts/ .

我的问题是,当我长按单元格时出现错误:

 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConcreteMapTable gestureRecognizerShouldBegin:]: unrecognized selector sent to instance 0x7b6bea30'

我试图通过调试器找到故障线,但似乎找不到它。它甚至在到达gestureRecognizerShouldBegin之前就中断了

这是我的布局文件:

import UIKit
import Sapporo

let SecondsMaximum : CGFloat = 10
let ChannelsMaximum : CGFloat = 6
let HorizontalSpacing : CGFloat = 10
let VerticalSpacing : CGFloat = 4
//let WidthPerSecond : CGFloat = 100
let SecondHeaderHeight : CGFloat = 40
let ChannelHeaderWidth : CGFloat = 100

class PulseLayout: SALayout, UIGestureRecognizerDelegate {
override func collectionViewContentSize() -> CGSize {

let contentHeight = collectionView!.bounds.size.height
let contentWidth = collectionView!.bounds.size.width
return CGSizeMake(contentWidth, contentHeight)
}

override func awakeFromNib() {
super.awakeFromNib()
self.setupGestureRecognizer()
}

override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {
var layoutAttributes = [UICollectionViewLayoutAttributes]()

// Cells
let visibleIndexPaths = indexPathsOfItemsInRect(rect)
layoutAttributes += visibleIndexPaths.map {
self.layoutAttributesForItemAtIndexPath($0)
}

// Supplementary views
let secondHeaderViewIndexPaths = indexPathsOfSecondHeaderViewsInRect(rect)
layoutAttributes += secondHeaderViewIndexPaths.map {
self.layoutAttributesForSupplementaryViewOfKind(PulseHeaderType.Second.rawValue, atIndexPath: $0)
}

let channelHeaderViewIndexPaths = indexPathsOfChannelHeaderViewsInRect(rect)
layoutAttributes += channelHeaderViewIndexPaths.map {
self.layoutAttributesForSupplementaryViewOfKind(PulseHeaderType.Channel.rawValue, atIndexPath: $0)
}

// Decoration Views
let verticalGridViewIndexPaths = indexPathsOfVerticalGridLineViewsInRect(rect)
layoutAttributes += verticalGridViewIndexPaths.map {
self.layoutAttributesForDecorationViewOfKind(GridLineType.Vertical.rawValue, atIndexPath: $0)
}
let horizontalGridViewIndexPaths = indexPathsOfHorizontalGridLineViewsInRect(rect)
layoutAttributes += horizontalGridViewIndexPaths.map {
self.layoutAttributesForDecorationViewOfKind(GridLineType.Horizontal.rawValue, atIndexPath: $0)
}

return layoutAttributes
}

override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
var attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)

if let event = (getCellModel(indexPath) as? PulseEventCellModel)?.event {
attributes.frame = frameForEvent(event)
}
return attributes
}

override func layoutAttributesForSupplementaryViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
var attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, withIndexPath: indexPath)

let totalHeight = collectionViewContentSize().height
let totalWidth = collectionViewContentSize().width

if elementKind == PulseHeaderType.Second.rawValue {
let availableWidth = totalWidth - ChannelHeaderWidth
let widthPerSecond = availableWidth / SecondsMaximum
attributes.frame = CGRectMake(ChannelHeaderWidth + widthPerSecond * CGFloat(indexPath.item), 0, widthPerSecond, SecondHeaderHeight)
attributes.zIndex = -10
} else if elementKind == PulseHeaderType.Channel.rawValue {
let availableHeight = totalHeight - SecondHeaderHeight
let heightPerChannel = availableHeight / ChannelsMaximum
attributes.frame = CGRectMake(0, SecondHeaderHeight + (heightPerChannel * CGFloat(indexPath.item)), ChannelHeaderWidth, heightPerChannel)
attributes.zIndex = -10
}
return attributes
}


override func layoutAttributesForDecorationViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
var attributes = UICollectionViewLayoutAttributes(forDecorationViewOfKind: elementKind, withIndexPath: indexPath)

let totalHeight = collectionViewContentSize().height
let totalWidth = collectionViewContentSize().width

if elementKind == GridLineType.Vertical.rawValue {
let availableWidth = totalWidth - ChannelHeaderWidth
let widthPerSecond = availableWidth / SecondsMaximum
attributes.frame = CGRectMake(ChannelHeaderWidth + widthPerSecond * CGFloat(indexPath.item), 0.0, 1, totalHeight)
attributes.zIndex = -11
} else if elementKind == GridLineType.Horizontal.rawValue {
let availableHeight = totalHeight - SecondHeaderHeight
let heightPerChannel = availableHeight / ChannelsMaximum
attributes.frame = CGRectMake(0.0, SecondHeaderHeight + (heightPerChannel * CGFloat(indexPath.item)), totalWidth, 1)
attributes.zIndex = -11
}
return attributes
}



override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
return true
}


struct Bundle {
var offset : CGPoint = CGPointZero
var sourceCell : UICollectionViewCell
var representationImageView : UIView
var currentIndexPath : NSIndexPath
var canvas : UIView
}
var bundle : Bundle?

var canvas : UIView? {
didSet {
if canvas != nil {
// self.calculateBorders()
}
}
}

func setupGestureRecognizer() {
if let collectionView = self.collectionView {

let longPressGestureRecogniser = UILongPressGestureRecognizer(target: self, action: "handleGesture:")

longPressGestureRecogniser.minimumPressDuration = 0.2
longPressGestureRecogniser.delegate = self

collectionView.addGestureRecognizer(longPressGestureRecogniser)

if self.canvas == nil {

self.canvas = self.collectionView!.superview

}
}
}


func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {

if let ca = self.collectionView!.superview {

if let cv = self.collectionView {

let pointPressedInCanvas = gestureRecognizer.locationInView(ca)

for cell in cv.visibleCells() as! [PulseEventCell] {

let cellInCanvasFrame = ca.convertRect(cell.frame, fromView: cv)

if CGRectContainsPoint(cellInCanvasFrame, pointPressedInCanvas ) {

let representationImage = cell.snapshotViewAfterScreenUpdates(true)
representationImage.frame = cellInCanvasFrame

let offset = CGPointMake(pointPressedInCanvas.x - cellInCanvasFrame.origin.x, pointPressedInCanvas.y - cellInCanvasFrame.origin.y)

let indexPath : NSIndexPath = cv.indexPathForCell(cell as UICollectionViewCell)!

self.bundle = Bundle(offset: offset, sourceCell: cell, representationImageView:representationImage, currentIndexPath: indexPath, canvas: ca)
break
}

}

}

}
return (self.bundle != nil)
}

func handleGesture(gesture: UILongPressGestureRecognizer) -> Void {


if let bundle = self.bundle {

let dragPointOnCanvas = gesture.locationInView(self.collectionView!.superview)

if gesture.state == UIGestureRecognizerState.Began {

bundle.sourceCell.hidden = true
self.canvas?.addSubview(bundle.representationImageView)

UIView.animateWithDuration(0.5, animations: { () -> Void in
bundle.representationImageView.alpha = 0.8
});

}


if gesture.state == UIGestureRecognizerState.Changed {

// Update the representation image
var imageViewFrame = bundle.representationImageView.frame
var point = CGPointZero
point.x = dragPointOnCanvas.x - bundle.offset.x
point.y = dragPointOnCanvas.y - bundle.offset.y
imageViewFrame.origin = point
bundle.representationImageView.frame = imageViewFrame


let dragPointOnCollectionView = gesture.locationInView(self.collectionView)


if let indexPath : NSIndexPath = self.collectionView?.indexPathForItemAtPoint(dragPointOnCollectionView) {

// self.checkForDraggingAtTheEdgeAndAnimatePaging(gesture)


if indexPath.isEqual(bundle.currentIndexPath) == false {

// If we have a collection view controller that implements the delegate we call the method first
/*if let delegate = self.collectionView!.delegate as UICollectionViewDelegate? {
delegate.moveDataItem(bundle.currentIndexPath, toIndexPath: indexPath)
}*/

self.collectionView!.moveItemAtIndexPath(bundle.currentIndexPath, toIndexPath: indexPath)

self.bundle!.currentIndexPath = indexPath

}

}


}

if gesture.state == UIGestureRecognizerState.Ended {


bundle.sourceCell.hidden = false
bundle.representationImageView.removeFromSuperview()

if let delegate = self.collectionView!.delegate as UICollectionViewDelegate? { // if we have a proper data source then we can reload and have the data displayed correctly
self.collectionView!.reloadData()
}

self.bundle = nil
}
}
}
}
extension PulseLayout {
func indexPathsOfEventsBetweenMinSecondIndex(minChannelIndex: Int, maxChannelIndex: Int, minStartSecond: Int, maxStartSecond: Int) -> [NSIndexPath] {
var indexPaths = [NSIndexPath]()

if let cellmodels = getCellModels(0) as? [PulseEventCellModel] {
for i in 0..<cellmodels.count {
let event = cellmodels[i].event
if event.channel >= minChannelIndex && event.channel <= maxChannelIndex && event.startSecond >= minStartSecond && event.startSecond <= maxStartSecond {
let indexPath = NSIndexPath(forItem: i, inSection: 0)
indexPaths.append(indexPath)
}
}
}
return indexPaths
}

func indexPathsOfItemsInRect(rect: CGRect) -> [NSIndexPath] {
let minVisibleChannel = channelIndexFromYCoordinate(CGRectGetMinY(rect))
let maxVisibleChannel = channelIndexFromYCoordinate(CGRectGetMaxY(rect))
let minVisibleSecond = secondIndexFromXCoordinate(CGRectGetMinX(rect))
let maxVisibleSecond = secondIndexFromXCoordinate(CGRectGetMaxX(rect))

return indexPathsOfEventsBetweenMinSecondIndex(minVisibleChannel, maxChannelIndex: maxVisibleChannel, minStartSecond: minVisibleSecond, maxStartSecond: maxVisibleSecond)
}

func channelIndexFromYCoordinate(yPosition: CGFloat) -> Int {

let contentHeight = collectionViewContentSize().height - SecondHeaderHeight
let HeightPerChannel = contentHeight / ChannelsMaximum

let channelIndex = max(0, Int((yPosition - SecondHeaderHeight) / HeightPerChannel))
return channelIndex
}

func secondIndexFromXCoordinate(xPosition: CGFloat) -> Int {

let contentWidth = collectionViewContentSize().width - ChannelHeaderWidth
let WidthPerSecond = contentWidth / SecondsMaximum

let secondIndex = max(0, Int((xPosition - ChannelHeaderWidth) / WidthPerSecond))
return secondIndex

}

func indexPathsOfSecondHeaderViewsInRect(rect: CGRect) -> [NSIndexPath] {
if CGRectGetMinY(rect) > SecondHeaderHeight {
return []
}

let minSecondIndex = secondIndexFromXCoordinate(CGRectGetMinX(rect))
let maxSecondIndex = secondIndexFromXCoordinate(CGRectGetMaxX(rect))

return (minSecondIndex...maxSecondIndex).map { index -> NSIndexPath in
NSIndexPath(forItem: index, inSection: 0)
}
}

func indexPathsOfChannelHeaderViewsInRect(rect: CGRect) -> [NSIndexPath] {
if CGRectGetMinX(rect) > ChannelHeaderWidth {
return []
}

let minChannelIndex = channelIndexFromYCoordinate(CGRectGetMinY(rect))
let maxChannelIndex = channelIndexFromYCoordinate(CGRectGetMaxY(rect))

return (minChannelIndex...maxChannelIndex).map { index -> NSIndexPath in
NSIndexPath(forItem: index, inSection: 0)
}
}

func indexPathsOfVerticalGridLineViewsInRect(rect: CGRect) -> [NSIndexPath] {
if CGRectGetMaxX(rect) < SecondHeaderHeight {
return []
}

let minSecondIndex = secondIndexFromXCoordinate(CGRectGetMinX(rect))
let maxSecondIndex = secondIndexFromXCoordinate(CGRectGetMaxX(rect))

return (minSecondIndex...maxSecondIndex).map { index -> NSIndexPath in
NSIndexPath(forItem: index, inSection: 0)
}
}
func indexPathsOfHorizontalGridLineViewsInRect(rect: CGRect) -> [NSIndexPath] {
if CGRectGetMaxY(rect) < ChannelHeaderWidth {
return []
}

let minChannelIndex = channelIndexFromYCoordinate(CGRectGetMinY(rect))
let maxChannelIndex = channelIndexFromYCoordinate(CGRectGetMaxY(rect))

return (minChannelIndex...maxChannelIndex).map { index -> NSIndexPath in
NSIndexPath(forItem: index, inSection: 0)
}
}

func frameForEvent(event: PulseEvent) -> CGRect {
let totalHeight = collectionViewContentSize().height - SecondHeaderHeight
let HeightPerChannel = totalHeight / ChannelsMaximum

let contentWidth = collectionViewContentSize().width - ChannelHeaderWidth
let WidthPerSecond = contentWidth / SecondsMaximum


var frame = CGRectZero
frame.origin.x = ChannelHeaderWidth + WidthPerSecond * CGFloat(event.startSecond)
frame.origin.y = SecondHeaderHeight + HeightPerChannel * CGFloat(event.channel)
frame.size.height = HeightPerChannel
frame.size.width = CGFloat(event.durationInSeconds) * WidthPerSecond

frame = CGRectInset(frame, 2.0, HeightPerChannel/8.0)
return frame
}
}

这是我的 ViewController:

import UIKit
import Sapporo

enum PulseHeaderType: String {
case Second = "SecondHeaderView"
case Channel = "ChannelHeaderView"
}
enum GridLineType: String {
case Vertical = "VerticalGridLineView"
case Horizontal = "HorizontalGridLineView"
}

class PulseViewController: UIViewController {

@IBOutlet var collectionView: UICollectionView!

lazy var sapporo: Sapporo = { [unowned self] in
return Sapporo(collectionView: self.collectionView)
}()

override func viewDidLoad() {
super.viewDidLoad()
sapporo.delegate = self
sapporo.registerNibForClass(PulseEventCell)
sapporo.registerNibForSupplementaryClass(PulseHeaderView.self, kind: PulseHeaderType.Second.rawValue)
sapporo.registerNibForSupplementaryClass(PulseHeaderView.self, kind: PulseHeaderType.Channel.rawValue)

let layout = PulseLayout()
layout.registerClass(GridLineView.self, forDecorationViewOfKind: GridLineType.Vertical.rawValue)
layout.registerClass(GridLineView.self, forDecorationViewOfKind: GridLineType.Horizontal.rawValue)
sapporo.setLayout(layout)


let randomEvent = { () -> PulseEvent in
let randomID = arc4random_uniform(10000)
let title = "Event \(randomID)"

let randomChannel = Int(arc4random_uniform(6))
let randomStartSecond = Int(arc4random_uniform(8))
let randomDuration = Int(arc4random_uniform(2) + 1)

return PulseEvent(title: title, channel: randomChannel, startSecond: randomStartSecond, durationInSeconds: randomDuration)
}

let cellmodels = (0...20).map { _ -> PulseEventCellModel in
let event = randomEvent()
return PulseEventCellModel(event: event) { _ in
println("Selected event: \(event.title)")
}
}

sapporo[0].append(cellmodels)
sapporo.bump()
}
}

extension PulseViewController: SapporoDelegate {
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
if kind == PulseHeaderType.Second.rawValue {
let view = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: PulseHeaderView.reuseIdentifier, forIndexPath: indexPath) as! PulseHeaderView
view.titleLabel.text = "\(indexPath.item)"
return view
}

let view = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: PulseHeaderView.reuseIdentifier, forIndexPath: indexPath) as! PulseHeaderView
view.titleLabel.text = "Channel \(indexPath.item + 1)"
return view
}
}

你能帮我找出我缺少的东西吗?

问候,

C

最佳答案

我不久前解决了这个问题:

struct Bundle

func setupGestureRecognizer()

func gestureRecognizerShouldBegin

func handleGesture(gesture: UILongPressGestureRecognizer) -> Void

应该全部放入 ViewController 而不是布局文件中。

关于ios - 手势识别器应该开始 : Unrecognized selector sent to instance,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32313629/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com