I am trying to present a message viewController after pressing a button that is inside of a UiView. When I press the button, the message viewController presents itself, but it is missing some data. I have a separate viewController that allows me to push the controller. I will leave pictures below to show what I am talking about.
This is what the message view controller is supposed to look like, and this what the code looks like to get there
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
dismiss(animated: true) {
print("Dismiss completed")
let user = self.user[indexPath.row]
self.messagesController?.showChatControllerForUser(user)
}
}
This is what happens when I push the view from the UiView, and this is what the code looks like to get there.
#objc func handleNewMessage() {
let chatLogController = ChatLogController(collectionViewLayout: UICollectionViewFlowLayout())
chatLogController.user = user
let navVC = UINavigationController(rootViewController:chatLogController)
self.window?.rootViewController?.present(navVC, animated: true, completion: nil)
}
All of the data pushes through, but the back button is missing, and I am not allowed to actually send a message. I am using two different methods to get to the same controller and I am expecting to see the same result. I was wondering if someone possibly new how to fix this issue?
Back button is not displaying because you are presenting the chatLogController using below function.
#objc func handleNewMessage() {
let chatLogController = ChatLogController(collectionViewLayout: UICollectionViewFlowLayout())
chatLogController.user = user
let navVC = UINavigationController(rootViewController:chatLogController)
self.window?.rootViewController?.present(navVC, animated: true, completion: nil)
}
if you are push to chatLogController from messagesController then you are display a back button on chatLogController.
Note: back button is automatically display when you push to another viewController, it is not display when you present the viewController.
Related
i'm trying to create a view controller programmatically that will be opened if a cell on a table is clicked. i'm using a table view and i'm filling it with a xib.So, i'm stuck at the point of referencing the new view controller from the first one on click on a cell created in the table view via xib.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "DViewController") as? DViewController
self.navigationController?.present(vc!, animated: true, completion: nil) //present della view successiva
vc?.name = data[indexPath.row].nome
}
this code allows me to click on the row but when clicked it shows an error "Fatal error: Unexpectedly found nil while unwrapping an Optional value" generated apparently from the self.navigationController?.present(vc!...the vc value result to be nil and i can't figure out why.
THis is the ViewController that i want to open on click and the only thing that it has to do is open and change the tile to the name ow the cell that i've clicked onto in the other ViewController
class DViewController: UITableViewController {
var name = ""
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.topItem?.title = "\(name)"
}
}
Can someone help?i'm new to swift...ty
Based on what you mentioned. You can initialize your viewController without stroyboard, and there is no crash anymore.
let vc = DViewController()
If you present your view controller like what you did, it won’t display the title you wish.
To display the title, there are 2 ways you can do:
Display your new view controller with Pushing style:
let vc = DViewController()
navigationController?.pushViewController(vc, animated: true)
Keep using presenting style, but you need to wrap your view controller in other navigation controller:
let vc = DViewController()
let nav = UINavigationController(rootViewController: vc)
navigationController?.present(nav, animated: true)
I have controller1 -> TableViewController2 -> TableViewController3 in my storyboard. When I press a button in controller1, I want to jump to TableViewController3 and from there when I select a row, I want to go back to TableViewController2 and get some data and then go back to controller1.
In controller1 instantiate TableViewController3:
if segue.identifier == "MySegue" {
let viewController:TableViewController3 = segue.destination as! TableViewController3
viewController.addLocationToMap = true
}
In TableViewController3 instantiate TableViewController2 like this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if addLocationToMap == true {
let navc:UINavigationController = self.navigationController!
let tvc:UITableViewController = TableViewController2()
let rootView = navc.viewControllers[0]
navc.setViewControllers([rootView, tvc], animated: true)
return
}
In TableViewController2 viewDidLoad, it fails in ViewDidLoad when I try to set a text field value because the textfield is nil. It cannot be because Textfield is already in the view. Looks like the TableViewController2 view never got loaded.
in TableViewController2
override func viewDidLoad() {
super.viewDidLoad()
locationPurposeTextField.text = "sometext"
}
Fails when setting text value because locationPurposeTextField is nil.
How to fix this?
EDITS:
On pressing a button In controller1:
let navc:UINavigationController = self.navigationController!
let alTvc = self.storyboard!.instantiateViewController(withIdentifier: "AddLocationID") as! UITableViewController
navc.pushViewController(alTvc, animated: false)
let cListTvc = self.storyboard!.instantiateViewController(withIdentifier: "ContactListID") as! UITableViewController
navc.pushViewController(cListTvc, animated: true)
The code takes me to TableViewController3 with storyboard ID: ContactListID as desired.
Next, in TableViewController3
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.myDelegate?.userSelectedContact(contactIdentifier: self.contactId, contactFullName: fullName, contactSelected: true)
let navc:UINavigationController = self.navigationController!
let tvc:UITableViewController = self.storyboard!.instantiateViewController(withIdentifier: "AddLocationID") as! UITableViewController
let rootView = navc.viewControllers[0]
navc.setViewControllers([rootView, tvc], animated: true)
}
Takes me to TableViewController2 with storyboard ID: AddLocationID
Based on the delegate sent TableViewController3, in ViewDidappear method of TableViewController2, I set some text in the view and call tableview.realoadData(). It does not load the view.
However if I select a button in TableViewController2 and load TableViewController3 and then comeback to TableViewController2 upon execution of the very same method didSelectRow it reloads the view in TableViewController2
How to fix it, please let me know?
There are a couple of things wrong with your approach.
If you want to go from controller1 to TableViewController3 but have your navigation stack contain controller1 -> TableViewController2 -> TableViewController3, you will have to have the button in controller1 first push TableViewController2 without animation, and then push TableViewController3 with animation. (You won't be able to have your button trigger a segue.)
Second problem: You can't create a copy of your TableViewController2 by just invoking it's initializer (TableViewController2()). When you do that it doesn't load its views from the storyboard. Instead, you should assign a storyboard identifier to it and use the UIStoryboard method instantiateViewController(withIdentifier:) to create a new instance of it.
I didn't succeed to perform UIAlertController from UITableViewCell
I have already tried to create a segue programmatically and then perform it(code num 1), but it crash at appDelegate (the crash happened at appDelegate)
I tried to use code 2 and it did nothing(that printed :" whose view is not in the window hierarchy!" maybe it connected?),
I tried to call function in viewController.Swift to present and/or segue and it didn't succeed as well
the alert should appear only when a specific button in a cell is pressed
code 1:
UIApplication.shared.keyWindow?.rootViewController?.present(refreshAlert, animated: true, completion: nil)
code 2:
var segue = UIStoryboardSegue.init(identifier: "goAlart", source: ViewController(), destination: refreshAlert)
segue.perform()
the exception that I got at appDelegate is: Thread 1: signal SIGABRT
when I delete "segue.perform()" I got no errors
As mentioned in comments, good place to show the alert would be didSelectRow at.
I can't see the rest of the code, but I assume you have your UIAlertController initialised and property refreshAlert point's to it. If refreshAlert is stored in ViewController, then this should work:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
present(refreshAlert, animated: true, completion: nil)
}
EDIT:
Since you need to show the alert on button press in cell, good way to do so, would be a delegate protocol:
protocol MyCusomCellDelegate: NSObjectProtocol {
func didPressAlertButton()
}
In your cell, you declare delegate property:
weak var delegate: MyCusomCellDelegate?
On pressing the button, you call delegate method:
delegate?.didPressAlertButton()
In ViewController you conform to the protocol:
extension ViewController: MyCusomCellDelegate {
func didPressAlertButton() {
present(refreshAlert, animated: true, completion: nil)
}
}
And lastly, in cellForRowAt indexPath
cell.delegate = self
if you need to show different alert for different cells, then you should pass some data in the delegate call.
In "tableViewCell.swift," put:
weak var delegate:yourViewController!
and then you have access to all variables from viewController and all features, like:
present(refreshAlert, animated: true, completion: nil)
And, in "cellForRowAt indexPath," put:
cell.delegate = self
I'm new to swift and I'm trying to learn how to pass data between view controllers and use firebase along with it. This is my segue to a new controller with it setting a variable on that view controller I'm pushing to.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let viewController = storyboard?.instantiateViewController(withIdentifier: "UserInfoViewController") as! UserInfoViewController
viewController.uidPassed = userUIDArray[indexPath.row]
self.present(viewController, animated: true, completion: nil)
}
It segues to the new controller where I have the variable declared as a string. When I go to run this it crashes with it saying that the string was empty. I can print it and it is empty in the viewDidAppear method, but the viewDidLoad method it has the UID stored in the variable from when I clicked on in the previous controller. Am I not passing the variable from one view controller to the other correctly?
override func viewDidAppear(_ animated: Bool) {
databaseRef.child("Users").child(self.uidPassed).child("Name").observe(.value, with: { (snapshot) in
let name = snapshot.value as! String
print(name)
})
There are two main ways to pass data from one view controller to another view controller.
First, you can connect your cell with the destination view controller in storyboard. In this case you will define the type of segue in storyboard, and you need to define an identifier for the segue in storyboard. When you want to pass data, you need to do it in prepareForSegue method, like this
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationViewController = segue.destination as? YourTableViewController {
destinationViewController.texts = self.texts
//...
}
}
Second, you can do this programmatically, like what you are trying to do in your example. In this case you should not connect view controllers by segue in storyboard. Instead, you set an identifier for the destination view controller itself. Then you initiate that controller in the code, set properties to the initiated view controller object and then present it, like what you are doing in your example.
Hope that helps.
This sounds like a typing issue. It seems like userUIDArray holds an array of UID's (not sure what type this is), and you're trying to assign it to viewController.uidPassed, which sounds like it's expecting a string. Try this:
viewController.uidPassed = userUIDArray[indexPath.row] as! String
The other option is to change the type of uidPassed to whatever type of value the userUIDArray variable holds.
I have a segue setup in my swift class called ViewController and I am calling from a tableView didSelectRowAtIndexPath. I am using this code in my segue
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
var svc = segue!.destinationViewController as Homework;
svc.subject = subject_name
}
To tell it to set a varible called subject which is declared like this var subject:NSString! to a varible called subject_name. I then call it from my tableView didSelectRowAtIndexPath using this code prepareForSegue(UIStoryboardSegue(), sender: AnyObject?()).
This is my didSelectRowAtIndex
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
let indexPath = tableView.indexPathForSelectedRow();
var currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell
println(currentCell.textLabel!.text)
subject_name = currentCell.textLabel.text
// // Showing new storyboard
performSegueWithIdentifier("Homework", sender: self)
let vc : AnyObject! = self.storyboard.instantiateViewControllerWithIdentifier("Homework")
self.showViewController(vc as UIViewController, sender: vc)
}
But when I go and run the app, and click the table view cell I get this error "fatal error: unexpectedly found nil while unwrapping an Optional value", and a green arrow points towards var svc = segue!.destinationViewController as Homework;. I tested the exact same code out on another app expect with the segue being called when a button is clicked and that worked perfectly, I also tried answers from Calling segue programatically not working, and Preparing for segue in embedded tableView in Swift. Both of these answers did not work.
If I understood it correctly, you are calling prepareForSegue(). You shouldn't, that is automatically invoked.
What you should do instead is calling performSegueWithIdentifier(identifier: String, sender: AnyObject?). That triggers a segue invocation, which automatically executes prepareForSegue().
The identifier parameter is the one you set from IB: select the segue and look at the attributes inspector.
Besides that, #AnthonyKong's answer is a safer way to deal with optionals (a segue in this case) - that ensures that no runtime exception is thrown.
Addendum
Looking at your updated question, specifically at the implementation of didSelectRowAtIndexPath. The last 2 lines:
let vc : AnyObject! = self.storyboard.instantiateViewControllerWithIdentifier("Homework")
self.showViewController(vc as UIViewController, sender: vc)
are redundant - if you perform a segue, that will instantiate the destination view controller, so you don't have to do it manually. Remove those lines.
You should do this instead:
if let svc = segue!.destinationViewController as? Homework {
svc.subject = subject_name
}
It is because you might get passed other segues which do not have Homework as desination VC