Propertylist in array passed with segue - ios

So I am trying to create a app that is more or less a reference with static data and using a plist to store the data
I have two TableViewControllers setup on the storyboard and I wanna pass the selected cells rownumber or its data to the next view?
My initial setup:
import UIKit
var categoryNames:NSArray = []
var categorySelected:String = ""
class ListForbTVC: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
let path = NSBundle.mainBundle().pathForResource("listor", ofType: "plist")
let dict = NSDictionary(contentsOfFile: path!)
categoryNames = dict.objectForKey("Category") as NSArray
println(categoryNames.count)
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
For some reason I cannot figure out how to count the number of rows in the array?
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 13
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = categoryNames[indexPath.row] as? String
return cell
}
What should I add here to actually pass the value through the segue? Would be neat to know how to both pass the index of the selected row and how to pass the actual value of it.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "listData" {
}
How do I recieve the information in the next view?
I have done this in obj-c and X-Code 5 but I cannot figure out how to do this in Swift.
Thanks in advance

You can simply declare a property in your second view controller - something like this -
class VC2 : UIViewController {
var someString:String?
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if (self.someString != nil) {
println("Some string =\(self.someString)")
}
}
}
Then in your prepareForSegue, simply set it
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "listData" {
let destVC=segue.destinationViewController as VC2
destVC.someString="Some value"
}
}

I have updated my answer as per swift.Please check.
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "segueTest") {
var svc = segue!.destinationViewController as secondViewController;
svc.toPass =data}
}
Please check this http://jamesleist.com/ios-swift-passing-data-between-viewcontrollers/
Let me know if faces issue still.

Related

Swift 4.2 - How to call "indexPath.row" from "didSelectRowAtIndexPath" method in a tableView to another class?

I have two viewControllers. One has a tableView which has some cells from an array; And the other is a viewController which contains a webkit that I want to present some local HTML files. Also I defined the webKit page as tableView's next page.
What I want is, when a user chooses a cell in the tableView, according to which cell is selected, it goes to webkit Page, and some parts of codes runs for user to show a specific HTML. In other words, I have 5 HTML files and 5 items in tableViewCells
so if a user chooses for example the first item, the HTML1 shows to him, if he chooses the second cell, the HTML2 present for him etc.
I tried a lot of ways. but nothing happened. also tried to create instance object from the tableview class...
tried also some same problem here ins StackOverFlow but not succeed
First Page:
var arr = ["masoud" , "hossein", "reza" , "shiva" , "fateme"]
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("item selected is : \(indexPath.row)")
// if indexPath.row == 1 {
performSegue(withIdentifier: "TableSegue", sender: nil)
//}
tableView.deselectRow(at: indexPath, animated: true)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch (segue.destination.view, segue.destination, sender) {
case let (_, controller as WebKitController, indexPath as NSIndexPath):
controller.indexPath = indexPath
break
default:
break
}
}
the Second Page:
import WebKit
class WebKitController: UIViewController, WKUIDelegate, WKNavigationDelegate {
#IBOutlet weak var myWebKit: WKWebView!
var reza : String = String()
var indexPath: NSIndexPath? {
didSet {
reza = (indexPath?.row.description)!
print(indexPath?.row as Any)
self.myWebKit.uiDelegate = self
self.myWebKit.navigationDelegate = self
}
}
override func viewDidLoad() {
super.viewDidLoad()
let url = Bundle.main.url(forResource: "reza", withExtension: "html", subdirectory: "ReZeynoo2")!
myWebKit.loadFileURL(url, allowingReadAccessTo: url)
let request = URLRequest(url: url)
myWebKit.load(request)
self.myWebKit.uiDelegate = self
self.myWebKit.navigationDelegate = self
}
As an alternative approach
I would store not a simple array but struct of name and bool is selected or not
struct CellData {
let name: String!
let isSelected: Bool!
let index: Int!
init(name: String, isSelected: Bool, index: Int) {
self.name = name
self.isSelected = isSelected
self.index = index
}
}
Then in didSelectAtRow func will make selected the cell which tapped and use this info in prepare for segue func
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.deselectAll()
self.cellItems[indexPath.row].isSelected = true
performSegue(withIdentifier: "TableSegue", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch (segue.destination.view, segue.destination, sender) {
case let (_, controller as WebKitController, indexPath as NSIndexPath):
if let item = cellItems.first(where: {$0.isSelected == true}) {
controller.indexPath = item.index
}
break
default:
break
}
}
private func deselectAll() {
for item in cellItems {
item.isSelected = false
}
}
You need to create a Int variable in WebKitController class as selectedRow where the selected row will get assigned from table view cell selection,
// MARK: - Table view delegates
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "TableSegue", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "TableSegue", let indexPath = sender as? IndexPath {
let webController = segue.destination as? WebKitController
webController.selectedRow = indexPath.row
}
}
I think you can pass your indexpath.row value in sender of your perfomSegue and your second view controller just use this
here is code
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "secondvc", sender: indexPath.row)
}
just send indexpath.row value in sender
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "secondvc"{
let vc = segue.destination as! SecondViewController
vc.row = sender as! Int
}
}

viewDidLoad() not running after segue

I'm performing a segue from one table view to another.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
NSLog("You selected cell number: \(indexPath.row)!")
self.performSegue(withIdentifier: "types", sender: productList[indexPath.row])
}
It should run the viewDidLoad() of the new TableView described by the custom class of the ViewController (Which I've declared in Storyboard)
func viewDidLoad(parent: String) {
print("This should print")
super.viewDidLoad()
//self.typeTableView.delegate = self
//self.typeTableView.dataSource = self
//Set reference
ref = Database.database().reference()
//Retrieve posts
handle = ref?.child(parent).observe(.childAdded, with: { (snapshot) in
let product = snapshot.key as? String
if let actualProduct = product
{
self.productList.append(actualProduct)
self.typeTableView.reloadData()
}
})
}
Any Idea why this might be happening?
Embed navigation controller to your destination controller
and make a segue from current table views cell to it with identifier types.
Then add below method after your
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "types" {
if let indexPath = tableView.indexPathForSelectedRow {
let object = productList[indexPath.row] as! yourProductType
let controller = (segue.destination as! UINavigationController).topViewController as! YourDestinationViewController
controller.yourProductProperty = object
}
}
}
Make sure to declare yourProductProperty in your Destination controller so that you can access current product object in it.
viewDidLoad has no parameters and needs an override clause:
override func viewDidLoad() {
...
}
Your method signature is
func viewDidLoad(parent: String) {
but it should be
override func viewDidLoad() {
super.viewDidLoad()
// Your code
}
are you using same class to tableviewcell ? if yes then keep different identifier [RESUE IDENTIFIER] for both tableview.

Pass data to segued controller found nil using Prepareforsegue

I have the following class I am segueing to.
class FriendsProfileViewController: UIViewController {
var user : User!
override func viewDidLoad() {
super.viewDidLoad()
print(user.firstName)
}
}
On the segueing class I did the following to pass the data
var friends: [User]?
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("viewFriend", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destinationVC = segue.destinationViewController
if let friendsProfileVC = destinationVC as? FriendsProfileViewController{
if let indexPath = sender as? NSIndexPath{
print(indexPath.row)
friendsProfileVC.user = friends?[indexPath.row]
}
}
}
Why is it that I am getting the error
fatal error: unexpectedly found nil while unwrapping an Optional value
even though my friend?[indexPath.row] is verified to contain a value when I segue?.
Try getting the user before performing the segue and pass it as the segue sender.
var friends: [User]?
private func friend(at index: Int) -> User? {
return friends.flatMap { $0.indicies.contains(index) ? $0[index] : nil }
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let friend = friend(at: indexPath.row) {
performSegueWithIdentifier("viewFriend", sender: friend)
} else {
print("Invalid index: \(indexPath.row)")
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
switch (segue.destinationViewController, sender) {
case (let controller as FriendsProfileViewController, let user as User):
controller.user = user
default:
break
}
}
The issue I believe is that we always get back an Optional from array as such friends![indexPath.row] returned an Optional(User).
I ended up passing the an Optional User as the sender. Unwrap it and set it to my other VC.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("viewFriend", sender: friends![indexPath.row])
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
print(sender)
let destinationVC = segue.destinationViewController
if let friendsProfileVC = destinationVC as? FriendsProfileViewController{
if let friend = sender as? User{
print(friend)
print(friend.firstName)
friendsProfileVC.user = friend
}
}
}
Update, I have tried changing friendsProfileVC.user = friends?[indexPath.row] to friendsProfileVC.user = friends![indexPath.row] and it worked. Not sure why did it not work earlier on.

Searched item returns wrong detail view on click

I am parsing some info from JSON using Firebase. I implemented search controller into the tableview, it returns correct items while searching but the problem is that on click (didSelectRowAtIndexPath) it returns wrong info. What could cause this, can you tell me guys?
This is the arrays in which I am searching:
var brands = [String]()
And this is the filtered array:
var filteredBrands = [String]()
And this is what I am doing inside the didSelectRowAtIndexPath:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedBrand = brands[indexPath.row]
performSegueWithIdentifier("toProducts", sender: self)
}
And like this I pass the selected value:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if (segue.identifier == "toProducts") {
let snusProductsView = segue.destinationViewController as! SnusProductsTableViewController
snusProductsView.brandName = selectedBrand
print(self.selectedBrand)
}
}
But for some reason it passes the wrong value. It passes the first item inside tableView
Inside didSelectRowAtIndexPath you have to check is it filtered version or not if so you need to use filteredBrands instead of brands.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if isSearching {
selectedBrand = filteredBrands[indexPath.row]
} else {
selectedBrand = brands[indexPath.row]
}
I must be dumb... After posting I figured out what was the problem. My selectedBrand was wrong if the resultSearchController was active. So I fixed it like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if (segue.identifier == "toProducts") {
let snusProductsView = segue.destinationViewController as! SnusProductsTableViewController
snusProductsView.brandName = selectedBrand
print(self.selectedBrand)
}
}

Passing CoreData keys to new ViewController

I am working on one part of my app which will function as a journal for the user, in which they can add an entry, then review or delete them afterwards. I followed a few Swift tutorials for CoreData and I have confirmed that the CoreData setup is working. However, I am having trouble getting values to pass to the UIViewController that will display the journal after already being saved. In one configuration I had tried it displayed no data, in another the data would stay the same no matter what entry selected, and in the setup below, this line journalEntryViewer.journalViewerTextView.text = journalTextToPass returns "found nil when unwrapping optional value."
Here is the code for the UITableViewController that acts as the list:
import UIKit
import CoreData
class JournalCollectionViewer: UITableViewController {
var JournalEntry = [NSManagedObject]()
var journalTextToPass:String!
var journalTitleToPass:String!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
self.tableView.reloadData()
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "JournalEntry")
do {
let results =
try managedContext.executeFetchRequest(fetchRequest)
JournalEntry = results as! [NSManagedObject]
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
// MARK: - Table view data source
#IBOutlet weak internal var journalCollectionTable: UITableView!
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return JournalEntry.count
}
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCellWithIdentifier("JournalCell")
let entry = JournalEntry[indexPath.row]
cell!.textLabel!.text =
entry.valueForKey("journalDate") as? String
return cell!
}
func selectedTableCell(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let entry = self.JournalEntry[indexPath.row]
self.performSegueWithIdentifier("ShowEntryViewer", sender: entry)
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowEntryViewer" {
let journalEntryViewer = segue.destinationViewController as! JournalEntryViewer
journalEntryViewer.self.navigationItem.title = journalTitleToPass
journalEntryViewer.journalViewerTextView.text = journalTextToPass
}
}
}
In the Swift file for the viewer (journalEntryViewer), all I have done is declared the class and the UITextView. Needless to say, I am at a loss. Any help appreciated!
When you assign value to the IBOutlet object in the prepareForSegue method that time it is not initialized, so you need to pass the string object and assign that string object to the journalViewerTextView in the viewDidLoadof JournalEntryViewer.
First declare two instance var in the JournalEntryViewer like this
var journalTitle: String?
var journalText: String?
Now use this var in viewDidload
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = journalTitle
self.journalViewerTextView.text = journalTitle
}
Now pass this journalTitle and journalText in the prepareForSegue method of JournalCollectionViewer
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowEntryViewer" {
let journalEntryViewer = segue.destinationViewController as! JournalEntryViewer
journalEntryViewer.journalTitle = journalTitleToPass
journalEntryViewer.journalText = journalTextToPass
}
}
New Edit:
Problem with your code is you have not used delegate method didSelectRowAtIndexPath instead of you are using something else selectedTableCell that is wrong try to implement delegate method of UITableView
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let entry = self.JournalEntry[indexPath.row]
self.performSegueWithIdentifier("ShowEntryViewer", sender: entry)
}
Now you are passing entry object so change your prepareForSegue like this
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowEntryViewer" {
let journalEntryViewer = segue.destinationViewController as! JournalEntryViewer
let entry = sender as! NSManagedObject
journalEntryViewer.journalTitle = entry.valueForKey("journalDate") as? String
journalEntryViewer.journalText = entry.valueForKey("journalEntryText") as? String
}
}

Resources