This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 3 years ago.
I have a button in News Tab, And I want pass value to Competition Tab by any way.
But the problem is not passing correct value.
My code is-
//NewsViewController
#IBAction func fullStndngAction(_ sender: Any) {
//I Tried this
let prefs = UserDefaults.standard
prefs.set(true, forKey: "isFromNewsView")
//I Tried This as well
let whereFrom = storyboard?.instantiateViewController(withIdentifier: "LatestNewsDetailViewController") as? LatestNewsDetailViewController
whereFrom!.isFromNewsView = true
self.tabBarController?.selectedIndex = 1
}
But always I am getting false in competition view.
Image description-
Try one of the following solutions depending on each condition.
case 1: If your ViewController is embedded in a navigationController try this: -
if let competitionsVC = self.tabBarController.viewControllers?[1].children.first as? CompetitionViewController {
competitionVC.isFromNewsView = true
self.tabBarController?.selectedIndex = 1
}
Case 2: If your ViewController is not embedded in navigationController
if let competitionVC = self.tabBarController.viewControllers?[1] as? CompetitionViewController {
competitionVC.isFromNewsView = true
self.tabBarController?.selectedIndex = 1
}
Explanation: For case one since the VC which you are looking for is embedded in navigationController then you have cast down the way to it's child which is the VC you are looking for. For case two there is no navigationController so you cast direct to the VC you are looking for, ie.. no need to find child like on case 1.
Related
I've been looking through a Coordinator tutorial and it brought up a problem with code I've written in the past.
Namely, when reusing a view controller I've used a property to be able to display different elements depending on which view controller the user arrived from. This is described in the above tutorial as a hack.
For example I segue to labelviewcontroller using
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "label" {
let vc = segue.destination as! LabelViewController
vc.originalVC = self
}
}
and then on labelViewController have a property
var originalVC: ViewController?
which I then change the items in viewDidLoad() through
override func viewDidLoad() {
super.viewDidLoad()
if originalVC != nil {
label.text = "came direct"
imageView.isHidden = true
}
else {
label.text = "button"
imageView.isHidden = false
}
}
I've a working example project here: https://github.com/stevencurtis/ReusibilityIssues
Now, I know the answer might be use the Coordinator tutorial, but is there any other method that I can use to simple reuse a viewController for two different circumstances, rather than using a property or is there anyway to clean this up to be acceptable practice?
You can do that without passing originalVC just by checking parent type if you are pushing it inside a navigation controller like this :
if let p = parent {
if p.isKind(of: OriginalViewController.self){
//it pushed in navigation controller stack after OriginalViewController
}
}
but is there any other method that I can use to simple reuse a viewController for two different circumstances
If the "two different circumstances" you describe are very different (by this I mean "require very different lines of code to be run"), then you should create two different view controller classes, because otherwise you would be violating the Single Responsibility Principle.
If your "two different circumstances" are different, but also quite related, then you can just have all the information that the VC needs to know as properties. You certainly don't need a whole ViewController.
For example, if your LabelViewController will show a "foo" button only if it is presented by ViewControllerFoo.
You can add a showFooButton property in LabelViewController:
var showFooButton = false
override func viewDidLoad() {
fooButton.isHidden = !showFooButton
}
And then in ViewControllerFoo.prepareForSegue:
if segue.identifier == "label" {
let vc = segue.destination as! LabelViewController
vc.showFooButton = true
}
I wouldn't call this a hack. This is the recommenced way described in this post and they didn't call it a hack.
so I created a chat view controller using the JSQMessagesViewController following this tutorial here: https://learnappmaking.com/chat-app-ios-firebase-swift-xcode/#comment-1930 my code is more or less the same, I didn't tweak anything significant in it, the tutorial is only for a single view controller so I added another view controllers for the app but every time it perform segues, I get the error SIGABRT, no matter if I segues with performSegue or with the back button in navigation bar, it keeps giving signal SIGABRT. any help would be appreciated.
this is my viewdidload:
override func viewDidLoad() {
super.viewDidLoad()
senderId = "1111"
senderDisplayName = "Bob"
title = "Steve"
inputToolbar.contentView.leftBarButtonItem = nil
collectionView.collectionViewLayout.incomingAvatarViewSize = CGSize.zero
collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSize.zero
let query = Constants.refs.databaseChats.queryLimited(toLast: 10)
_ = query.observe(.childAdded, with: { [weak self] snapshot in
if let data = snapshot.value as? [String: String],
let id = data["sender_id"],
let name = data["name"],
let text = data["text"],
!text.isEmpty
{
if let message = JSQMessage(senderId: id, displayName: name, text: text)
{
self?.messages.append(message)
self?.finishReceivingMessage()
}
}
})
// Do any additional setup after loading the view.
}
SIGABRT (signal abort) is typically from a referencing error in your storyboard. Did you ever change the name of a class or make a connection from a button of one view controller to another and then delete it? If you changed the name of a class you must make the sure the name in the code of the class matches that. If you deleted a button connection between view controllers, click on the controller itself and under the connections tab you must delete it.
I want to pass data from firstViewController -> secondNavigationcontroller -> secondTabBarController -> secondViewcontroller.
I can pass it to my navigationcontroller like this:
if segue.identifier == "StartMatchSegue" {
if let destination = segue.destination as? SecondNavigationController {
destination.delegate = self as? UINavigationControllerDelegate
destination.testString = "lets play"
}
}
but I cant figure out how to pass it all the way.
storyboard
You could also create a singleton which can be accessed within each view controller.
You can pass data in different ways two of them i have mentioned below.
NotitificationCenter
Closure
I am new to swift and I am trying to make this note app. I have split view controller that goes in my first view controller and that view controller connects to a table view controller. Everything works perfectly is just that when I launch the app I have all the notes like I want but when I try to go back to my first view controller and come back to my table view controller, all the notes are duplicated every single time I do it. I tried everything I can try, is there anyone who can help me
my MasterViewController is
import UIKit
class MasterViewController: UITableViewController {
var detailViewController: DetailViewController? = nil
override func viewDidLoad()
{
super.viewDidLoad()
Note.loadNotes() // The problem is here, I think
noteTable = self.tableView
// Do any additional setup after loading the view, typically from a nib.
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject(_:)))
navigationItem.rightBarButtonItem = addButton
if let split = splitViewController
{
let controllers = split.viewControllers
detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
}
My loadNotes function is
class func loadNotes()
{
let defaults:UserDefaults = UserDefaults.standard
let saveData: [NSDictionary]? = defaults.object(forKey: kAllNotes) as? [NSDictionary]
if let data:[NSDictionary] = saveData
{
for i:Int in 0 ..< data.count
{
let n:Note = Note()
n.setValuesForKeys(data[i] as! [String : Any])
allNotes.append(n)
}
}
}
Your loadNotes method keeps appending. The first line of loadNotes should be:
allNotes = [Note]()
Then it starts with an empty array and fills it up.
And why is loadNotes a static method? That's a bad design. Make Notes a normal class and make loadNotes an instance method.
On an unrelated note (no pun intended), do not use UserDefaults to store app data. Only use it to store little bits of information.
I am swift beginner and I am struggling with my first application. Sorry if my question is too basic, but I get an error message in my code here:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
let secVC: NavigationViewController = segue.destinationViewController as! NavigationViewController // here is the error
secVC.receiveImeNaSladkarnica = Label1.text!
secVC.KordaA = Shirina.text!
secVC.KordaB = Duljina.text!
secVC.PodImeNaObekt = Label2.text!
I have created 2 different buttons: Navi Me and More Info buttons.
The first one (Navi Me) is connected with another view controller which is called NavigationViewContorller, there I send all of the data I need by using prepare for segue. Everything was working perfect, but now I have created another button which is called (MoreInfo).It is connected with 3rd viewcontroller called MoreInfoViewController. I think I have connected everything fine, but still when I click on the MoreInfo button the app stops working and I get the following error: Thread 1: signal SIGBART in the marked line. I cannot understand why is it breaking when this segue is for another view controller, nt for the MoreInfoViewController. Would you please advice me what to do or provide me with an example how to fix it
I have tried that:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
switch segue.identifier {
//error here-> case "VC1" :
let secVC: NavigationViewController = segue.destinationViewController as! NavigationViewController
secVC.receiveImeNaSladkarnica = Label1.text!
secVC.KordaA = Shirina.text!
secVC.KordaB = Duljina.text!
secVC.PodImeNaObekt = Label2.text!
//error here -> case "VC2" :
let secVC2: MoreInfoViewController = segue.destinationViewController as! MoreInfoViewController
secVC2.receiveImeNaSladkarnica = Label1.text!
secVC2.KordaA = Shirina.text!
secVC2.KordaB = Duljina.text!
secVC2.PodImeNaObekt = Label2.text!
default:
break
It still doesn't work
Each segue is supposed to have an unique string identifier.
For multiple view controllers use a switch statement
switch segue.identifier {
case "vc1" :
// prepare to go to vc1
case "vc2" :
// prepare to go to vc2
default : break
}
Once again my yesterday comment:
Since you are a beginner in Swift please learn first to consider the naming convention that variable names start with a lowercase letter.