How to pass only one key value pair from array? - ios

The following is my json response....
{"Doctor":[{"doctorname":"ANBU SURESH RAO, D.ORTHO., MSORTHO.,","presid":"1008"}]}
The following is my viewcontroller code.......
let parameters: Parameters=["hnum":hnum!]
Alamofire.request(URL_USER_LOGIN, method: .post, parameters: parameters).responseJSON
{
response in
let result = response.result
if let dict = result.value as? Dictionary<String,AnyObject>{
if let innerDict = dict["Doctor"]{
self.namesarray = innerDict as! [AnyObject]
self.jsontable.reloadData()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return namesarray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? CustomTableViewCell
let name = namesarray[indexPath.row]["doctorname"]
cell?.lbldocname.text = name as? String
flag = !flag
flagcheck()
return cell!
}
This view controller loads only my doctor name, so when i click the doctor name I want the presid only to be passed on to the next view controller.... I tried with prepareForSegue it didnt work....any ideas????

tableView:didSelectRowAtIndexPath:
Tells the delegate that the specified row is now selected. Use indexPath to locate the new selected row in tableView.
Check my previous SO ans for details.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let pressId = namesarray[indexPath.row]["presid"]
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondViewController ") as? SecondViewController {
viewController.pressId= pressId
if let navigator = navigationController {
navigator.pushViewController(viewController, animated: true)
}
}
}
Declare a global variable pressId in SecondViewController so that you can access it from your current controller class.

Declare a global variable selectedPresId. Implement didSelectRowAtIndexPath method and in that method set the pres id in that global variable
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedPresId = namesarray[indexPath.row]["presid"]
self.performSegue(withIdentifier: "detailSegue", sender: self)
}
In prepareForSegue do this
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detailSegue" {
let vc = segue.destination as! ViewController
vc.selectedPresId = selectedPresId
}
And in your second view controller create a property with the name - selectedPresId so that you can set it in above line vc.selectedPresId

Related

I want to display Array from UITableView to the next viewController using didSelectRowAt

I want the quizNumber to return the quizNumberArray depending on which cell is selected.
For example, if the user selected the first cell the quizNumber returns 1
Inside the UITableViewController
let quizNumberArray = [1,2,3,4,5,6,7,8,9,10]
var quizNum = Int()
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "toQuestionVC") as? QuestionVC
quizNum = quizNumberArray[indexPath.row]
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
if identifier == "toQuestionVC" {
let questionController = segue.destination as! QuestionVC
questionController.quizNumber = quizNum
}
in the next ViewController
class QuestionVC : UIViewController {
var quizNumber = Int()
func updateQuestion(){
if quizNumber == 1 {
//.....
}
}
}
But the quizNumber return 0.
Try this Code:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "toQuestionVC") as? QuestionVC
vc?.quizNumber = quizNumberArray[indexPath.row]
navigationController?.pushViewController(vc!, animated: true)
}
and remove the segue to work the above code

How to pass indexPath value from performSegue() to prepareForSegue()

I have a tableView in a SubMenuViewController, when a user taps (using didSelectRowAt) on a cell and segues, I need to pass that cell to the next UserInputViewController,
Here is my code:
class SubMenuViewController: UIViewController {
//MARK: - Properties and outlets
var node: Node?
#IBOutlet weak var tableView: UITableView!
//MARK: - View controller methods
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.isNavigationBarHidden = false
self.navigationItem.title = node?.value.rawValue
let nib = UINib(nibName: "SubMenuTableViewCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "SubMenuCell")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "userInput" {
let vc = segue.destination as! UserInputViewController
let indexPath = sender as! IndexPath
vc.node = node?.childenNode[indexPath.row]
}
}
}
//MARK: UITableViewDataSource methods
extension SubMenuViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return node!.childCount
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubMenuCell", for: indexPath) as! SubMenuTableViewCell
let desciptionModule = node?.childenNode[indexPath.row].value
let description = Modules.description(module: desciptionModule!)
cell.title.text = description.main
cell.subtitle.text = description.sub
return cell
}
}
//MARK: - UITableViewDelegate methods
extension SubMenuViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 68
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
guard let selectedNode = node?.childenNode[indexPath.row] else {
return
}
if selectedNode.isLeaveNode() {
performSegue(withIdentifier: "userInput", sender: indexPath)
} else {
let subMenuViewController = self.storyboard!.instantiateViewController(withIdentifier: "subMenu") as! SubMenuViewController
subMenuViewController.node = selectedNode
//let subMenuViewController = SubMenuViewController(node: selectedNode)
self.navigationController?.pushViewController(subMenuViewController, animated: true)
}
}
}
Right now, in my performSegue, I passed in my indexPath into the sender, and I should expect to get it back in prepareForSegue, but I can't. Any suggestions guys?
Thanks
In my opinion it isn't very good practice to pass the index path (or any other value that counts a s "data") as the sender argument; as its name suggests, it is intended for passing the object that sent the message (i.e., called the action method), in this case self (you could "relay" the original sender if your action method calls another action method instead, but that's off-topic here).
As #sCha kindly pointed out in the comments, the Apple documentation on this method in particular, though, seems to leave room for doubt nevertheless. The parameter name sender clearly comes from the homonimous argument in all control actions that follow Cocoa's target/action pattern.
My suggestion:
The best you can do I think is to store the index path in a property of your view controller:
var selectedIndexPath: IndexPath?
...set it on tableView(_:didSelectRowAt:):
if selectedNode.isLeaveNode() {
self.selectedIndexPath = indexPath
performSegue(withIdentifier: "userInput", sender: indexPath)
} else {
self.selectedIndexPath = nil
// ...
...and retrieve it (while resetting the property) in the prepareForSegue(_:sender:) implementation of the target view controller:
if let vc = segue.source as? SubmenuViewController {
if let indexPath = vc.selectedIndexPath {
vc.selectedIndexPath = nil // (reset it, just to be safe)
// Use indexPath...
}
}

TableView is Nil

I have the following class:
import UIKit
import CloudKit
class FirstViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var listTableView: UITableView!
var list: TLListModel!
var specificList: CKRecord!
override func viewDidLoad()
{
super.viewDidLoad()
let myContainer = CKContainer.default()
list = TLListModel(container: myContainer, viewController: self)
if(listTableView != nil){
listTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("number of items: %i", list.lists.count)
return list.lists.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = listTableView.dequeueReusableCell(withIdentifier: "cell")! as UITableViewCell
let list: CKRecord = self.list.lists[(indexPath as NSIndexPath).row]
cell.textLabel?.text = list.value(forKey: "ListName") as? String
cell.textLabel?.font = UIFont (name: "Slim Joe", size: 20)
cell.accessoryType = .disclosureIndicator
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("This object has been selected")
print(self.list.lists[(indexPath as NSIndexPath).row])
specificList = self.list.lists[(indexPath as NSIndexPath).row]
performSegue(withIdentifier: "TLSpecificListSegue", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "TLSpecificListSegue"{
if let destinationVC = segue.destination as? TLSpecificListViewController{
destinationVC.listObject = specificList
}
}
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
{
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
{
if editingStyle == .delete
{
let cloudkit = TLCloudKitHelper()
cloudkit.deleteListItem(self.list.lists[(indexPath as NSIndexPath).row], callback: { (listName) in
TLAlertHelper.notifyUser("List Deleted", message: NSString(format: "List for %# successfully deleted", listName) as String, sender: self)
let myContainer = CKContainer.default()
self.list = TLListModel(container: myContainer, viewController: self)
DispatchQueue.main.async {
self.listTableView.reloadData()
}
})
}
}
}
When I call it from another view controller using the following method:
#IBAction func createListAction(_ sender: AnyObject) {
let cloudkit = TLCloudKitHelper()
let listArray = createListFromTextField(textInputArea.text)
if(!(listNameTextField.text?.isEmpty)!){
cloudkit.createList(listNameTextField.text!) { (response) in
let listId = response
if (!listArray.isEmpty){
for item in listArray{
cloudkit.saveItemRecord(item, listId: listId, recordName: response)
}
}
let fvc: FirstViewController = FirstViewController()
DispatchQueue.main.async {
self.present(fvc, animated: true, completion: nil)
}
}
}else{
TLAlertHelper.notifyUser("Give the list a name", message: "You need to give you list a name...", sender:self)
}
}
I get an error saying fatal error: unexpectedly found nil while unwrapping an Optional value
I don't understand why I am getting this error. I've tried looking at the answers here: Simple UITableView in Swift - unexpectedly found nil but I none of those answers helped. Can someone tell me why this this crashing and how I can fix it?
The problem is this line:
let fvc: FirstViewController = FirstViewController()
This creates a blank FirstViewController instance — one completely unconnected with the interface you designed in the storyboard. Its view is empty. It has no table view in it. Therefore, since there is no table view, there is no outlet connection from any table view, and listTableView remains nil.
What you want to do is get the FirstViewController instance from the storyboard, the one whose interface you have already designed in the storyboard. You can do that by talking to the storyboard and using the FirstViewController's identifier, i.e., call instantiateViewController(withIdentifier:). (You might have to give the FirstViewController in the storyboard an identifier for this purpose.)
EDIT This is such a common mistake that I've written a blog post about it: http://www.programmingios.net/dont-make-a-new-instance-by-mistake/

TableViewCell to ViewController - Swift

I tried many ways but still can't go to another ViewController. This is my storyboard.
and This is my code.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? HistoryMainTableViewCell {
listItems.sort() { $0.seq > $1.seq }
let history = listItems[indexPath.row]
cell.setValue(history: history)
return cell
} else {
return HistoryMainTableViewCell()
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "vcProductHistory" {
if let productHistoryPage = segue.destination as? HistoryProductViewController {
if let IndexPath = tableViewHistory.indexPathForSelectedRow {
let historyArray = listItems[IndexPath.row]
productHistoryPage.history = historyArray
}
}
}
}
Try this code:(Untested Code)
Note: Below code will trigger prepare segue. When, tableViewCell selected.Let me know the code works...
func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
// let indexPath = myTableView!.indexPathForSelectedRow
// let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
//sendSelectedData = (currentCell.textLabel?.text)! as String as NSString
performSegue(withIdentifier: "vcProductHistory", sender: self)
}
Based on your answer to my initial comment: dragging the line from initial vc to destination vc tells your vc about the segue, preparing for segue tells your vc what do when the segue is triggered, but you still need to let your vc know when it should perform the segue. try this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? HistoryMainTableViewCell else { return HistoryMainTableViewCell() }
let history = listItems[indexPath.row]
cell.setValue(history: history)
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "vcProductHistory" {
guard let productHistoryPage = segue.destination as? HistoryProductViewController, let indexPath = sender as? IndexPath else { return }
let historyArray = listItems[indexPath.row]
productHistoryPage.history = historyArray
}
}
func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
performSegue(withIdentifier: "vcProductHistory", sender: indexPath)
}
I think this is a little bit neater using the guard syntax. Also, it uses sender as the indexPath, not using tableView.indexPathForSelectedRow.
Also, I noticed you have this in your cellForRowAtIndexPath:
listItems.sort() { $0.seq > $1.seq }
Your sorting your data source in cellForRowAtIndexPath. You can't do that there because that function gets called for each row individually. You need to do the sorting before that is called, somewhere like viewWillAppear. Also, to sort an array in place you need to remove the () after sort. try this.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
listItems.sort { $0.0.seq > $0.1.seq }
tableView.reloadData()
}
I think you should connect to UINavigationController , not to HistoryProductionViewController
Because your MainViewController's segue connected to Navigation Controller
I guess in func prepareForSegue segue.identifier == "vcProductHistory" it works but, if let productHistoryPage = segue.destination as? HistoryProductViewController not works
because your destination ViewController's class is NavigationController
you should call
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "vcProductHistory" {
if let naviVC = segue.destination as? UINavigationController {
if let productHistoryPage = naviVC.topViewController as? HistoryProductViewController {
if let IndexPath = tableViewHistory.indexPathForSelectedRow {
let historyArray = listItems[IndexPath.row]
productHistoryPage.history = historyArray
}
}
}
}
}
Your solution - as you described it - should work.
The most work here can be done directly in the Storyboard.
Select the prototype cell in the TableView, drag the Segue to the NavigationController and select presentModally.
This should work without further magic.
When selecting the TableViewCell the NavigationController should be presented. There is also no code needed at this point (except for the population of the TableView).
If not - you maybe misconfigured your TableView by setting the selection to No Selection:
or you set User Interaction Enabled to false somewhere.

How to Segue from Custom TableViewCell to Another ViewController (Swift)

I am attempting to navigate from a TableViewCell to a detail VC indicating details about the current business that is on the cell. Here are the stub tableiewMethods:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("YelpTableBusinessCell", forIndexPath: indexPath) as! YelpTableBusinessCell
var business:Business = Business(dictionary: businessArray[indexPath.row] as! NSDictionary)
cell.business = business
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
businessToUseTVC = Business(dictionary: businessArray[indexPath.row] as! NSDictionary)
performSegueWithIdentifier("businessToDetailVC", sender: view);
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let cell = sender as? YelpTableBusinessCell {
if segue.identifier == "businessToDetailVC" {
if let ivc = segue.destinationViewController as? AttractionsDetailViewController {
ivc.businessToUse = self.businessToUseTVC
}
}
}
}
I set two breakpoints, one at the prepareForSegue method and one at the didSelectRowAtIndexPath method
I initialize businessToUseVTC variable in didSelectRowAtIndexPath, but when I run the app, when I am at the AttractionsDetailVC, which contains this bit of code,
func loadYelpInfo() {
businessName.text = businessToUse.name
let thumbImageViewData = NSData(contentsOfURL: businessToUse.imageURL!)
thumbImage.image = UIImage(data: thumbImageViewData!)
let reviewImageData = NSData(contentsOfURL: businessToUse.ratingImageURL!)
reviewImage.image = UIImage(data: reviewImageData!)
categories.text = businessToUse.categories
reviews.text = "\(businessToUse.reviewCount!) Reviews"
distanceLabel.text = businessToUse.distance
}
the code breaks, saying that businessToUse, set inside DetailsVC, is nil.
Any help would be greatly appreciated.
First, make sure you ctrl drag from the VIEWCONTROLLER, not the individual cell.
Second, the sender is not of type YelpTablseBusinessCell, i believe this is your problem.

Resources