Dropping into NSBox subclass doesn't work - swift

I have created NSBox subclass to implement drag-and-drop. I followed this tutorial. Code looks like this:
import Cocoa
class EditCard: NSBox, NSDraggingSource, NSPasteboardItemDataProvider, NSPasteboardWriting {
var value: String = "0"
let supportedTypes: [NSPasteboard.PasteboardType] = [.string]
func highlight() {
self.borderColor = NSColor.controlAccentColor
self.borderWidth = 2.0
}
func unhighlight() {
self.borderColor = NSColor.clear
self.borderWidth = 0.0
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
let canReadPasteboardObjects = sender.draggingPasteboard.canReadObject(forClasses: [NSString.self], options: nil)
if canReadPasteboardObjects {
highlight()
return .copy
}
return NSDragOperation()
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
sender.draggingDestinationWindow?.orderFrontRegardless()
guard let pasteboardObjects = sender.draggingPasteboard.readObjects(forClasses: [NSString.self], options: nil), pasteboardObjects.count > 0 else { return false }
pasteboardObjects.forEach { (object) in
//Add both views to group
}
sender.draggingDestinationWindow?.orderFrontRegardless()
return true
}
override func draggingEnded(_ sender: NSDraggingInfo) {
unhighlight()
}
override func draggingExited(_ sender: NSDraggingInfo?) {
unhighlight()
}
override func concludeDragOperation(_ sender: NSDraggingInfo?) {
highlight()
}
override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
return true
}
func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor context: NSDraggingContext) -> NSDragOperation {
return .copy
}
func pasteboard(_ pasteboard: NSPasteboard?, item: NSPasteboardItem, provideDataForType type: NSPasteboard.PasteboardType) {
switch type {
case .string:
guard let indexData = value.data(using: .utf8) else { return }
item.setData(indexData, forType: type)
default: break
}
}
func writableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] {
var types = [NSPasteboard.PasteboardType]()
types.append(.string)
return types
}
func pasteboardPropertyList(forType type: NSPasteboard.PasteboardType) -> Any? {
return nil
}
override func mouseDragged(with event: NSEvent) {
let pasteboardItem = NSPasteboardItem()
pasteboardItem.setDataProvider(self, forTypes: [.string])
let pdfData = self.dataWithPDF(inside: self.bounds)
let imageFromPDF = NSImage(data: pdfData)
let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem)
draggingItem.setDraggingFrame(self.bounds, contents: imageFromPDF)
beginDraggingSession(with: [draggingItem], event: event, source: self)
}
override func awakeFromNib() {
self.wantsLayer = true
self.registerForDraggedTypes(supportedTypes)
}
}
I want to have this view to work both ways. Dragging this view works, but other views of the same subclass don't highlight when putting dragged view over it. When I try to print() on any function that accepts dragging (draggingEntered(), performDragOperation(), etc) nothing prints. Can somebody help me?

Related

Difficulty with Drag and Drop

I'm having difficulty understanding how to implement simple drag and drop in a macOS application. What I want to do is make a TextField that can accept a directory or file that is dropped onto it and capture the URL to that directory or file.
With the code shown below, my print("dragging entered") line does fire when I drag an object onto the TextField control, however when I release it the performDragOperation doesn't fire.
Can anyone please help me understand simple drag and drop?
Thanks
import Cocoa
class DropTextField: NSTextField {
var dragTypes : [NSPasteboard.PasteboardType] = [.fileURL, .URL]
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
}
override func awakeFromNib() {
self.registerForDraggedTypes(dragTypes)
}
public override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
return true
}
public override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
print("dragging engtered")
return NSDragOperation.copy
}
public override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
print("drag operation")
return true
}
}
Assign this custom class to the NSTextField object on the storyboard and create an outlet in the controller:
public class DragTextField: NSTextField {
public var completionHandler: (URL) -> Void = { fileURL in Swift.print(fileURL) }
public override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation { return NSDragOperation.copy }
public override func draggingUpdated(_ sender: NSDraggingInfo) -> NSDragOperation { return NSDragOperation.copy }
public override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
let pboard = sender.draggingPasteboard
if let fileURLFromClipboard = pboard.string(forType: NSPasteboard.PasteboardType.fileURL) {
let sourceFileURL = URL(string: fileURLFromClipboard)!
print(sourceFileURL)
completionHandler(sourceFileURL)
}
return true
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
stringValue = "Drop File Here";
isEditable = false
wantsLayer = true;
layer?.backgroundColor = NSColor.blue.cgColor
// Register for file name drag
registerForDraggedTypes([NSPasteboard.PasteboardType.fileURL])
}
}
Usage:
class ViewController: NSViewController {
#IBOutlet weak var dropView: DragTextField!
override func viewDidLoad() {
super.viewDidLoad()
dropView.completionHandler = {
print("File Path: \($0)")
}
}
}

IGListSectionController's didUpdate and cellForItem always re-called, even though isEqual == true

Trying to implement the IGListKit library, I'm running into the issue that my cells are updated unnecessarily. I'm using a singleton adapter.dataSource with one section per row in the table.
Minimum example:
import IGListKit
class ContentItem: ListDiffable {
weak var item: Content?
weak var section: ContentSectionController?
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
return true
}
init(item: Content?) {
self.item = item
}
}
class ContentSectionController: ListSectionController {
weak var object: ContentItem?
override func didUpdate(to object: Any) {
self.object = object as? ContentItem
self.object?.section = self
// should only be called on updates
}
override func sizeForItem(at index: Int) -> CGSize {
guard let content = object?.item else {
return CGSize(width: 0, height: 0)
}
// calculate height
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell = collectionContext!.dequeueReusableCellFromStoryboard(withIdentifier: "ContentCell", for: self, at: index)
(cell as? ContentCell)?.item = object // didSet will update cell
return cell
}
override init() {
super.init()
self.workingRangeDelegate = self
}
}
extension ContentSectionController: ListWorkingRangeDelegate {
func listAdapter(_ listAdapter: ListAdapter, sectionControllerWillEnterWorkingRange sectionController: ListSectionController) {
// prepare
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerDidExitWorkingRange sectionController: ListSectionController) {
return
}
}
class ContentDataSource: NSObject {
static let sharedInstance = ContentDataSource()
var items: [ContentItem] {
return Content.displayItems.map { ContentItem(item: $0) }
}
}
extension ContentDataSource: ListAdapterDataSource {
func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
return items
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
return ContentSectionController()
}
func emptyView(for listAdapter: ListAdapter) -> UIView? {
return nil
}
}
/// VC ///
class ContentViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let updater = ListAdapterUpdater()
adapter = ListAdapter(updater: updater, viewController: self, workingRangeSize: 2)
adapter.collectionView = collectionView
adapter.dataSource = ContentDataSource.sharedInstance
}
var adapter: ListAdapter!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
adapter.performUpdates(animated: true)
}
// ...
}
On every view appear I call adapter.performUpdates(animated: true), which should never update the cells since isEqual is overridden with true. Nonetheless, all cells' didUpdate is triggered, calling cellForItem again too.
IGListKit requires both diffIdentifier and isEqual to be implemented with the IGListDiffable protocol in order to compare the identity/equality of two objects. (You're missing the diff identifier in your model).
My understanding is that under the hood, ListKit checks to see if the two diff identifiers of the objects are equal, if they are THEN it moves on to comparing them with isEqual.
Resources:
IGListKit Best Practices
IGListDiffable Protocol Reference

Sending a string from one viewcontroller to another using delegate in swift

I'm trying to make a button click in PopupViewController fill a textfield in DagbogsindlaegViewController with a string "svimmelhed, ".
I'm not getting any errors when running the code, but the text is not there when i run the app simulation and press "ButtonPressSvimmelhed" in the class PopupViewController.
Is there a kind stranger who can help me and tell me what i am doing wrong?
Code below:
import UIKit
import EventKit
class DagbogsindlaegViewController: UIViewController{
#IBAction func BackToSVC(_ sender: Any){
self.performSegue(withIdentifier: "BackToSVCSegue", sender: self)
}
#IBAction func ToCalenderButtonPress(_ sender: Any) {
self.performSegue(withIdentifier: "ToCalenderSegue", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
TitleTextField.delegate = self
DescriptionTextField.delegate = self
// Do any additional setup after loading the view.
}
#IBOutlet weak var TitleTextField: UITextField!
#IBOutlet weak var DescriptionTextField: UITextField!
func addEventToCalendar(title: String, description: String?, startDate: Date, endDate: Date, completion: ((_ success: Bool, _ error: NSError?) -> Void)? = nil) {
let eventStore = EKEventStore()
eventStore.requestAccess(to: .event, completion: { (granted, error) in
if (granted) && (error == nil) {
let event = EKEvent(eventStore: eventStore)
event.title = title
event.startDate = startDate
event.endDate = endDate
event.notes = description
event.calendar = eventStore.defaultCalendarForNewEvents
do {
try eventStore.save(event, span: .thisEvent)
} catch let e as NSError {
completion?(false, e)
return
}
completion?(true, nil)
} else {
completion?(false, error as NSError?)
}
})
}
#IBAction func ButtonPressGemDagbog(_ sender: Any) {
addEventToCalendar(title: "\(String(describing: TitleTextField.text!))", description: "\(String(describing: DescriptionTextField.text!))", startDate: NSDate() as Date, endDate: NSDate() as Date)
}
#IBAction func ButtonPressPopupMenu(_ sender: Any) {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PopupViewControllerID") as! PopupViewController
self.addChild(popOverVC)
popOverVC.view.frame = self.view.frame
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParent: self)
}
}
extension DagbogsindlaegViewController : UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
extension DagbogsindlaegViewController : TextFraPopupDelegate {
func Symptomer(Svimmelhed: String) {
TitleTextField.text = Svimmelhed
}
}
And the other view controller:
import UIKit
protocol TextFraPopupDelegate{
func Symptomer(Svimmelhed: String)
}
class PopupViewController: UIViewController {
var symptomDelegate: TextFraPopupDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.showAnimate()
self.view.backgroundColor = UIColor.black.withAlphaComponent(0.8)
// Do any additional setup after loading the view.
}
#IBAction func ButtonPressBackToDagbogsindlaeg(_ sender: Any) {
self.removeAnimate()
//self.view.removeFromSuperview()
}
func showAnimate()
{
self.view.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.view.alpha = 0.0;
UIView.animate(withDuration: 0.25, animations: {
self.view.alpha = 1.0
self.view.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
});
}
func removeAnimate()
{
UIView.animate(withDuration: 0.25, animations: {
self.view.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.view.alpha = 0.0;
}, completion:{(finished : Bool) in
if (finished)
{
self.view.removeFromSuperview()
}
});
}
#IBAction func ButtonPressSvimmelhed(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
} else {
sender.isSelected = true
}
symptomDelegate?.Symptomer(Svimmelhed: "Svimmelhed, ")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
}
As mentioned in the comments the delegate is not set.
However in Swift there is a more convenient way to pass the string back to the presenting view controller, a callback closure. You get rid of the protocol and of the duty to set the delegate
Delete
protocol TextFraPopupDelegate{
func Symptomer(Svimmelhed: String)
}
In PopupViewController replace
var symptomDelegate: TextFraPopupDelegate?
with
var callback : ((String) -> Void)?
and
#IBAction func ButtonPressSvimmelhed(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
} else {
sender.isSelected = true
}
symptomDelegate?.Symptomer(Svimmelhed: "Svimmelhed, ")
}
with
#IBAction func ButtonPressSvimmelhed(_ sender: UIButton) {
sender.isSelected.toggle()
callback?("Svimmelhed, ")
}
In DagbogsindlaegViewController in ButtonPressPopupMenu add the closure
#IBAction func ButtonPressPopupMenu(_ sender: Any) {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PopupViewControllerID") as! PopupViewController
self.addChild(popOverVC)
popOverVC.view.frame = self.view.frame
popOverVC.callback = { string in
self.TitleTextField.text = string
}
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParent: self)
}
Finally delete
extension DagbogsindlaegViewController : TextFraPopupDelegate {
func Symptomer(Svimmelhed: String) {
TitleTextField.text = Svimmelhed
}
}
Notes:
The syntax (_ success: Bool, _ error: NSError?) -> Void)? is outdated. Since Swift 3 the parameter labels are gone, this is sufficient: (Bool, NSError?) -> Void)?
Don't use NS... classes in Swift if there are native counterparts for example Date
Please conform to the naming convention to name variables and functions / methods with a starting lowercase letter.
The syntax "\(String(describing: TitleTextField.text!))" is double redundant. You create a string from a string from a string. Replace it with TitleTextField.text!

Spring load NSOutlineView leaf rows

I've subclassed NSOutlineView and implemented NSSpringLoadingDestination, but springLoadingActivated() is only ever called on non-leaf rows, even though I've implemented springLoadingEntered() and springLoadingUpdated() to indiscriminately return [.enabled]. I assume NSOutlineView's built-in drag & drop support is interfering with my attempts. Is there a workaround for this?
Feels a little hacky, but it seems I can get away with this by spring loading the rows, but also overriding all of the NSDraggingDestination methods to pass the word on to the parent NSOutlineView:
class SpringLoadedOutlineRow: NSTableCellView, NSSpringLoadingDestination {
var outlineView: NSOutlineView! {
didSet {
registerForDraggedTypes(outlineView.registeredDraggedTypes)
}
}
//Pass through `NSDraggingDestination` methods so we don't interfere with `NSOutlineView`
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
return outlineView.draggingEntered(sender)
}
override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
return outlineView.prepareForDragOperation(sender)
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
return outlineView.performDragOperation(sender)
}
override func concludeDragOperation(_ sender: NSDraggingInfo?) {
outlineView.concludeDragOperation(sender)
}
override func draggingExited(_ sender: NSDraggingInfo?) {
outlineView.draggingExited(sender)
}
//Only pass through if we're expandable & not yet expanded (to get `NSOutlineView`'s default disclosure spring-loading); otherwise it will eat our leaf spring-loading
override func draggingUpdated(_ sender: NSDraggingInfo) -> NSDragOperation {
guard let representedItem = outlineView.item(atRow: outlineView.row(for: self)) else { return outlineView.draggingUpdated(sender) }
if outlineView.isExpandable(representedItem) && !outlineView.isItemExpanded(representedItem) {
return outlineView.draggingUpdated(sender)
} else {
return []
}
}
//Actually spring-load!
func springLoadingActivated(_ activated: Bool, draggingInfo: NSDraggingInfo) {
//Whatever you want
}
func springLoadingHighlightChanged(_ draggingInfo: NSDraggingInfo) {
}
func springLoadingEntered(_ draggingInfo: NSDraggingInfo) -> NSSpringLoadingOptions {
return [.enabled]
}
func springLoadingUpdated(_ draggingInfo: NSDraggingInfo) -> NSSpringLoadingOptions {
return [.enabled]
}
}

Swift: Building a Menu in a CollectionView With CollectionViewCell Segue

I am building a menu using CollectionView and programmatically trying to attach 5 buttons. I can not figure out how to connect the buttons to segues. The buttons activate a container view which then switches content within that view. This is what I have so far for the MenuContainerViewController which is embedded within a MainMenuViewController. Any help would be appreciated.
import UIKit
class MenuContainerViewController: UIViewController {
var firstVC: MainMenuViewController?
enum SegueIdentifier: String {
case SegueToTravelViewIdentifier = "SegueToTravelViewIdentifier"
case SegueToHistoryViewIdentifier = "SegueToHistoryViewIdentifier"
case SegueToLimitsViewIdentifier = "SegueToLimitsViewIdentifier"
case SegueToBalanceViewIdentifier = "SegueToBalanceViewIdentifier"
case SegueToEditViewIdentifier = "SegueToEditViewIdentifier"
case SegueToHelpViewIdentifier = "SegueToHelpViewIdentifier"
init?(optionalRawValue: String?) {
if let value = optionalRawValue {
switch value {
case "SegueToTravelViewIdentifier": self = .SegueToTravelViewIdentifier
case "SegueToHistoryViewIdentifier": self = .SegueToHistoryViewIdentifier
case "SegueToLimitsViewIdentifier": self = .SegueToLimitsViewIdentifier
case "SegueToBalanceViewIdentifier": self = .SegueToBalanceViewIdentifier
case "SegueToEditViewIdentifier": self = .SegueToEditViewIdentifier
case "SegueToHelpViewIdentifier": self = .SegueToHelpViewIdentifier
default: return nil
}
}
return nil
}
}
var vc : UIViewController!
var segueIdentifier : String!
var lastViewController: UIViewController!
override func viewDidLoad() {
super.viewDidLoad()
segueIdentifierReceivedFromParent("mainButton")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func segueIdentifierReceivedFromParent(button: String){
if button == "mainButton"
{
self.segueIdentifier = "main"
self.performSegueWithIdentifier(self.segueIdentifier, sender: nil)
}
else if button == "travelButton"
{
self.segueIdentifier = "travel"
self.performSegueWithIdentifier(self.segueIdentifier, sender: nil)
}
else if button == "balanceButton"
{
self.segueIdentifier = "balance"
self.performSegueWithIdentifier(self.segueIdentifier, sender: nil)
}
else if button == "limitsButton"
{
self.segueIdentifier = "limits"
self.performSegueWithIdentifier(self.segueIdentifier, sender: nil)
}
else if button == "historyButton"
{
self.segueIdentifier = "history"
self.performSegueWithIdentifier(self.segueIdentifier, sender: nil)
}
else if button == "helpButton"
{
self.segueIdentifier = "help"
self.performSegueWithIdentifier(self.segueIdentifier, sender: nil)
}
}
/*
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == segueIdentifier{
if lastViewController != nil{
lastViewController.view.removeFromSuperview()
}
vc = segue.destinationViewController
self.addChildViewController(vc)
vc.view.frame = CGRect(x: 0,y: 0, width: self.view.frame.width,height: self.view.frame.height)
self.view.addSubview(vc.view)
vc.didMoveToParentViewController(self)
lastViewController = vc
}
}
*/
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let segueIdentifierValue = SegueIdentifier(rawValue: segue.identifier!) {
if lastViewController != nil {
lastViewController.view.removeFromSuperview()
}
vc = segue.destinationViewController
self.addChildViewController(vc)
vc.didMoveToParentViewController(self)
lastViewController = vc
switch segueIdentifierValue {
case .SegueToTravelViewIdentifier:
print("travel")
case .SegueToHistoryViewIdentifier:
print("history")
case .SegueToLimitsViewIdentifier:
print("limits")
case .SegueToBalanceViewIdentifier:
print("balance")
case .SegueToEditViewIdentifier:
print("edit")
case .SegueToHelpViewIdentifier:
print("help")
}
}
}
}
and this is the MainMenuViewController:
class MainMenuViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UICollectionViewDelegate {
//Container View
#IBOutlet weak var contain: UIView!
//Slide Menu Collection View
let reuseIdentifier = "cell"
var menus = Array<String>()
var containerView: MenuContainerViewController?
#IBOutlet weak var collectionView: UICollectionView!
#IBAction func menuButtonPressed(sender: AnyObject) {
self.performSegueWithIdentifier("travel", sender: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
//Button names
menus = ["button_instore", "button_atm", "button_online", "button_travel", "button_balance", "button_limits", "button_history", "button_edit", "button_help"]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func travel(sender: AnyObject) {
containerView!.segueIdentifierReceivedFromParent("travelButton")
}
#IBAction func balance(sender: AnyObject) {
containerView!.segueIdentifierReceivedFromParent("balanceButton")
}
#IBAction func limits(sender: AnyObject) {
containerView!.segueIdentifierReceivedFromParent("limitsButton")
}
#IBAction func history(sender: AnyObject) {
containerView!.segueIdentifierReceivedFromParent("historyButton")
}
#IBAction func help(sender: AnyObject) {
containerView!.segueIdentifierReceivedFromParent("helpButton")
}
#IBAction func main(sender: AnyObject) {
containerView!.segueIdentifierReceivedFromParent("mainButton")
}
/*override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "container"{
containerView = segue.destinationViewController as? MenuContainerViewController
}
}
*/
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.navigationController?.navigationBar.translucent = true
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.menus.count
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
/*
func MenuContainerViewController(sender : UIButton) {
let selectedButtonCell = sender.superview as! UICollectionViewCell
let indexPath = collectionView.indexPathForCell(selectedButtonCell)
if indexPath!.row == 0 {
}
}
*/
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! CollectionViewCell
//cell.menuLabel.text = self.menus[indexPath.item]
cell.menuButton?.image = UIImage(named: menus[indexPath.row])
cell.menuButtonPressed.tag = indexPath.row
//cell.menuButtonPressed.addTarget(self, action: #selector(MenuContainerViewController), forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.item)!")
}
}