NSTableView, didSelectRowAt not being hit - swift

Ive searched for the answer, but the majority of examples ive found here and online are for IOS and im trying for OSX, sorry im not advanced enough to understand the IOS examples ive found online.
I can populate the table, so I know the delegate is working. but didSelectRowAt is not being hit?
here is my code, its from an example i found online and have tried to implement the didSelectRowAt.
import Cocoa
struct Task {
var schedule: String
var description: String
}
class ViewController: NSViewController {
#IBOutlet var tableView: NSTableView!
var items = [Task(schedule: "8:00 - 9:00", description: "Hacer ejercicios"),
Task(schedule: "9:00 - 13:00", description: "Trabajar")]
override func viewDidLoad() {
super.viewDidLoad()
// Add this
self.tableView.reloadData() // RECON THIS LOADS THE DATA TO TABLE
}
#IBAction func button(_ sender: Any) {
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewController: NSTableViewDelegate, NSTableViewDataSource {
func tableView(_ tableView: NSTableView, didSelectRowAt indexPath: IndexPath) {
print("Test")
}
func numberOfRows(in tableView: NSTableView) -> Int {
return self.items.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let currentItem = self.items[row]
if tableColumn?.identifier == NSUserInterfaceItemIdentifier(rawValue: "scheduleColumn") {
let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "scheduleCell")
guard let cellView = tableView.makeView(withIdentifier: cellIdentifier, owner: self) as? NSTableCellView else {
return nil
}
cellView.textField?.stringValue = currentItem.schedule
return cellView
} else if tableColumn?.identifier == NSUserInterfaceItemIdentifier(rawValue: "descriptionColumn") {
let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "descriptionCell")
guard let cellView = tableView.makeView(withIdentifier: cellIdentifier, owner: self) as? NSTableCellView else {
return nil
}
cellView.textField?.stringValue = currentItem.description
return cellView
}
return nil
}
}
im very new to swift. so please be nice,

You have the wrong delegate method. Try this one:
func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
print("Selected")
return true
}
I assume you were looking at the iOS UITableView method tableView(_:didSelectRowAt:):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { }
Just changing UITableView to NSTableView does not work -- by doing that, you just made a new method that is not part of the NSTableViewDelegate protocol. So, it will never be called.

Related

MFMailComposeViewController not showing Cancel button

I tried all the SOF solutions nothing work for my case.
My app is using tabbar and one of the tabbar is setting(tableview). User can tap on the support cell to send email.
I can bring up the email view but it doesn't have cancel button. Only way to dismiss it is to send the email or swipe down save/delete draft.
Thanks!!
import UIKit
import MessageUI
class SettingVC: UIViewController, UITableViewDelegate, UITableViewDataSource, MFMailComposeViewControllerDelegate {
#IBOutlet weak var tableView: UITableView!
let mail = MFMailComposeViewController()
var fromSetting: Bool = false
let settingsSction = ["Section0", "Section1", "Section2"]
let settingsCell = [["Cell0"],
["Cell1"],
["Cell2", "Support"]]
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.navigationController?.navigationBar.barStyle = .black
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func viewDidLoad() {
super.viewDidLoad()
setUpNavBar()
tableView.delegate = self
tableView.dataSource = self
mail.mailComposeDelegate = self
}
func setUpNavBar() {
self.navigationItem.titleView?.tintColor = .white
let settingsTitleLabel = UILabel()
settingsTitleLabel.textColor = .white
settingsTitleLabel.font = UIFont.boldSystemFont(ofSize: 18)
settingsTitleLabel.text = "Settings"
self.navigationItem.titleView = settingsTitleLabel
}
//MARK: Table View Sections
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func numberOfSections(in tableView: UITableView) -> Int {
return settingsSction.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return settingsSction[section]
}
//MARK: Table View Cell Title
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return settingsCell[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "\(settingsCell[indexPath.section][indexPath.row])"
cell.selectionStyle = .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch indexPath.section {
case 2:
switch indexPath.row {
case 1:
sendEmail()
default:
break
}
default:
break
}
}
func sendEmail() {
if MFMailComposeViewController.canSendMail() {
mail.navigationBar.tintColor = UIColor.orange
mail.setToRecipients(["support#example.com"])
mail.setSubject("I have an issue.")
self.present(mail, animated: true, completion: nil)
} else {
alertOK(title: "No Mail App Available", message: "Please install Mail app in your phone or use other mail app to send us the issue. Thank you.", sender: self)
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
}
Issue solved. I was setting the navigation bar color in app delegate so it makes the text white color as well.

What am I doing wrong on trying to set data to Struct

I'm trying to create a Struct to be able to pass data between screens. However, when I set data to my Struct properties and then I try to use it in another screen I got the value as "nil". What am I doing wrong?
Objects Struct:
import UIKit
struct Objetos {
var nome: String
var foto: UIImage
}
That's how I'm trying to set the value:
var objeto = Objeto(nome: "", foto: UIImage())
#IBAction func botaoAdcItem(_ sender: UIButton) {
if (self.namePreview!.text != nil) && (self.imagePreview!.image != nil) {
objeto?.nome = self.namePreview.text!
objeto?.foto = self.imagePreview.image!
self.navigationController?.popViewController(animated: true)
}
else { return }
}
That's how I'm trying to read the data:
class ViewController: UIViewController, CLLocationManagerDelegate, UITableViewDataSource {
#IBOutlet weak var itensTableView: UITableView!
var arrayNomes = NSMutableArray()
var objeto: Objetos?
var objetos = [Objetos]()
//TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
for nome in objetos {
arrayNomes.add(nome)
}
return arrayNomes.count //Nil value
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = itensTableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! tableviewCell
cell.nameCell.text = objeto?.nome //Nil value
cell.imageViewCell.image = objeto?.foto //Nil value
return cell
}
override func viewDidAppear(_ animated: Bool) {
self.itensTableView.reloadData()
}
Storyboard:
In your second code snippet, you never initialize objetos to anything. Thus, when you try to set one of the properties on objetos, nothing happens, because objetos doesn't exist.
Solution: Initialize objetos before trying to use it.
You can try this if you want to set the data to the previous VC
// ! won't crash
let count = self.navigationController.viewControllers!.count
let tab = self.navigationController.viewControllers![count-2] as! UITabBarController
let vc = tab.viewControllers![0] as! ViewController
vc.objetos.append(Objetos(name:self.namePreview.text!,foto:self.imagePreview.image!))
self.navigationController?.popViewController(animated: true)
plus
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = objectos[indexPath.row]
let cell = itensTableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! tableviewCell
cell.nameCell.text = item.nome //Nil value
cell.imageViewCell.image = item.foto //Nil value
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objetos.count
}
Try to replace
var objetos:Objetos?
with
var objeto = Objetos(nome: "", foto: UIImage())
you are starting your object as optional, and thus from the start is nil. When you try to assign properties in your struct you are failures because the object from the beginning is nonexistent
Regarding you other nil values, here is a revised view of your snippet
class ViewController: UIViewController, CLLocationManagerDelegate, UITableViewDataSource {
#IBOutlet weak var itensTableView: UITableView!
var objetos = [Objetos]()
//TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objetos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = itensTableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! tableviewCell
let objeto = objectos[indexPath.row]
cell.nameCell.text = objeto.nome
cell.imageViewCell.image = objeto.foto
return cell
}
override func viewWillAppear(_ animated: Bool) {
self.itensTableView.reloadData()
}
In your Additional Novo Itens Vc you are going to need to pass the created data back to your original View Controller, one way to do this is
#IBAction func botaoAdcItem(_ sender: UIButton) {
if (self.namePreview!.text != nil) && (self.imagePreview!.image != nil) {
// create the objecto
var objeto = Objetos(nome: namePreview.text,
foto: imagePreview.image)
// create a reference to your previous view controller
let vc = self.navigationController?.viewControllers[0] as! ViewController
// add objecto to objectos
vc.objetos.append(objeto)
self.navigationController?.popViewController(animated: true)
}
else { return }
}

Swift UiTableView not reloading search results

I am having a weird issue where for some reason my UITableView is not being reloading after performing a search. The console prints out the correctly filtered data, but the table simply doesn't change. I have never encountered this issue, so I first attempted the solutions which naturally came to mind:
Tried tableView.reloadData() in the Main Queue
Quit Xcode, clean build, reinstall
Cleared out the derived data dir
I have found several similar issue in SO, but all of the solutions I've seen are things I've tried, mainly reloading tableview in main queue.
Hoping maybe I just simply have an issue in my code or something I'm missing.
I am running Xcode 8.3.3
import UIKit
class CategoriesViewController: UIViewController {
var isFiltering = false
var location = Location()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
var categoriesSearchResults = [Category]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.allowsSelection = true
tableView.keyboardDismissMode = .onDrag
let nib = UINib(nibName: "CategoryTableViewCell", bundle: nil)
self.tableView.register(nib, forCellReuseIdentifier:"CategoryTableViewCell");
searchBar.returnKeyType = UIReturnKeyType.done
searchBar.autocapitalizationType = .none
searchBar.delegate = self
}
extension CategoriesViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("HI")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering {
return self.categoriesSearchResults.count
}
return self.location.categories.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as? CategoryTableViewCell {
var category: Category
if isFiltering {
category = self.categoriesSearchResults[indexPath.row]
} else {
category = self.location.categories[indexPath.row]
}
cell.name.text = category.name
cell.status.textColor = UIColor.lightGray
cell.status.text = "Not Verified"
}
return cell
}
}
extension CategoriesViewController : UISearchBarDelegate {
func searchBarIsEmpty() -> Bool{
return self.searchBar.text?.isEmpty ?? true
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
self.isFiltering = true
self.categoriesSearchResults.removeAll()
tableView.reloadData()
self.view.endEditing(true)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBarIsEmpty() {
self.view.endEditing(true)
self.isFiltering = false
} else {
self.isFiltering = true
self.categoriesSearchResults = self.location.categories.filter({ (category: Category) -> Bool in
return category.name.lowercased().contains(searchText.lowercased())
})
}
tableView.reloadData()
}
}
and my custom table view cell:
import UIKit
class CategoryTableViewCell: UITableViewCell {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var status: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func prepareForReuse() {
super.prepareForReuse()
self.name.text = ""
self.status.text = ""
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Thank you in advance.
EDIT: Might also be worth mentioning, when I am actively searching, the function tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) is not called??
The scope of if let nests in its scope. In your code you are always returning let cell = UITableViewCell(). Try returning it inside the if let :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as? CategoryTableViewCell {
var category: Category
if isFiltering {
category = self.categoriesSearchResults[indexPath.row]
} else {
category = self.location.categories[indexPath.row]
}
cell.name.text = category.name
cell.status.textColor = UIColor.lightGray
cell.status.text = "Not Verified"
/// RETURN CELL HERE
return cell
}
return cell
}

Swift 3.0 Autocomplete Address For Search Bar

I am interested in using a tableView to list possible addresses based on inputs in the search bar. After selecting the cell that contains the address desired, the search bar text consists of the address, however I want the possible addresses (cells) to disappear. Does self.searchResultsTableView.reloadData() in didSelectRowAt clear all the cells or is there another command? I am not certain how to clear the cells after selecting the appropriate address without iterating and having the suggestion introduce more cells.
import UIKit
import MapKit
class SearchViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
var searchCompleter = MKLocalSearchCompleter()
var searchResults = [MKLocalSearchCompletion]()
var searchSource: [String]?
#IBOutlet weak var searchResultsTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
searchCompleter.delegate = self
searchBar.delegate = self
}
}
extension SearchViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchCompleter.queryFragment = searchText
}
}
extension SearchViewController: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
searchResults = completer.results
searchResultsTableView.reloadData()
}
func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
// handle error
}
}
extension SearchViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchResults.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let searchResult = searchResults[indexPath.row]
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
cell.textLabel?.text = searchResult.title
cell.detailTextLabel?.text = searchResult.subtitle
return cell
}
}
extension SearchViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let completion = searchResults[indexPath.row]
let searchRequest = MKLocalSearchRequest(completion: completion)
let search = MKLocalSearch(request: searchRequest)
search.start { (response, error) in
let coordinate = response?.mapItems[0].placemark.coordinate
print(String(describing: coordinate))
print(response?.mapItems)
self.searchBar.text = response?.mapItems[0].name
}
self.searchResultsTableView.reloadData()
}
}
If you want to clear your tableView then you need to make your datasource array empty and then reload the tableView.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let completion = searchResults[indexPath.row]
let searchRequest = MKLocalSearchRequest(completion: completion)
let search = MKLocalSearch(request: searchRequest)
search.start { (response, error) in
let coordinate = response?.mapItems[0].placemark.coordinate
print(String(describing: coordinate))
print(response?.mapItems)
self.searchBar.text = response?.mapItems[0].name
}
//Make empty your array ant then reload tableView
searchResults = []
self.searchResultsTableView.reloadData()
}

Custom delegate method is calling

import UIKit
protocol CustomCellDelegate: class {
func liked(dataDict:NSDictionary,index:NSInteger)
}
class NameImageTextCell: UITableViewCell,UIActionSheetDelegate {
weak var delegateCell: CustomCellDelegate?
#IBAction func btnAction(_ sender: UIButton) {
if delegateCell==nil{
delegateCell?.liked(dataDict: dataNodeDict, index: ItemIndex)
}
}
}
////////
class
FanWallVC:UIViewController,UITableViewDelegate,UITableViewDataSource,
CustomCellDelegate {
#IBOutlet weak var tableView: UITableView!
let objNameImageTextCell = NameImageTextCell()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "NameImageTextCell", bundle: nil),
forCellReuseIdentifier: "NameImageTextCell")
objNameImageTextCell.delegateCell=self
}
func liked(dataDict: NSDictionary, index: NSInteger) {
print("Called")
}
}
When i Click on IBAction(btnAction) in NameImageTextCell, delegateCell is nil,
So liked method is not getting call.
Please help me.
Thanks in advance
You probably should call:
objNameImageTextCell.delegateCell = self
in
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}
so it should look somthing like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "NameImageTextCell", for: indexPath) as! NameImageTextCell
cell.delegateCell = self
//other cell customization
return cell
}