how to use segue after using webview? - swift

how do i perform segue when i exit the webview? it keeps throwing the sigbart error
class Sample: UIViewController, WKUIDelegate{
var url = String()
#IBOutlet var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string:"\(url)")
let myRequest = URLRequest(url: myURL!)
webView.configuration.preferences.javaScriptEnabled = true
webView.load(myRequest)
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
self.performSegue(withIdentifier: "toMain", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
webView.stopLoading()
}
}

Shouldn't have to do to with the webview if it is crashing on the segue. If you are trying to push to a new controller make sure you have your identifier set like below:
If you are just trying to go back one controller you can use:
self.dismiss(animated: true, completion: nil)
instead of:
self.performSegue(withIdentifier: "toMain", sender: self)
If you need to go back multiple views look into unwindToSegue functionality.
I would also consider moving the stopLoading function to viewWillDisappear since it has nothing to do with the segue itself.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.webView.stopLoading()
}

Related

How to pass different URL to webView from some buttons in swift?

I have some buttons in first view controller and a webView in second view controller. How to pass different url from different buttons to the webView? For example, the first button will leads to a google website and the second one is Facebook but using the same webView. Do I need to create different segues for each button or just one? If using just one, where should I start pulling that blue line (that line when you hold the control key)?
In first viewController:
class CafesView: UIViewController {
#IBOutlet weak var topBar: UIView!
#IBOutlet weak var button1: MDCFloatingButton!
#IBOutlet weak var button2: MDCRaisedButton!
#IBOutlet weak var button3: MDCRaisedButton!
#IBOutlet weak var button4: MDCRaisedButton!
#IBOutlet weak var button5: MDCRaisedButton!
#IBOutlet weak var button6: MDCRaisedButton!
#IBOutlet weak var button7: MDCRaisedButton!
#IBOutlet weak var button8: MDCRaisedButton!
#IBOutlet weak var button9: MDCRaisedButton!
let cafes = [
"Banana Joe's",
"College Eight Cafe",
"Global Village",
"Iveta",
"Oakes Cafe",
"Perk Coffee Bar",
"Stevenson Coffee House",
"Terra Fresca",
"Vivas"
]
var urlToPass: String!
override func viewDidLoad() {
super.viewDidLoad()
topBar.layer.shadowColor = UIColor.black.cgColor
topBar.layer.shadowOpacity = 0.5
topBar.layer.shadowOffset = CGSize(width: 0, height: 2)
topBar.layer.shadowRadius = 5
button1.layer.cornerRadius = 20
button2.layer.cornerRadius = 20
button3.layer.cornerRadius = 20
button4.layer.cornerRadius = 20
button5.layer.cornerRadius = 20
button6.layer.cornerRadius = 20
button7.layer.cornerRadius = 20
button8.layer.cornerRadius = 20
button9.layer.cornerRadius = 20
}
#IBAction func bananaJoes(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/pdf/banana-joes-menu.pdf"
}
#IBAction func collegeEightCafe(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/pdf/c8-menu.pdf"
}
#IBAction func globalVillage(_ sender: Any) {
urlToPass = "https://www.foodbooking.com/ordering/restaurant/menu?restaurant_uid=d368abee-3ccc-40d7-be7f-3ca5d4cbd513&glfa_cid=1263531392.1571083521&glfa_t=1571083566919"
}
#IBAction func iveta(_ sender: UIButton) {
urlToPass = "https://iveta.com/pages/iveta-ucsc-menu"
}
#IBAction func oakesCafe(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/pdf/oakes-menu-2019-20.pdf"
}
#IBAction func perkCoffeeBar(_ sender: UIButton) {
urlToPass = "https://google.com" //This url is just a placeholder
}
#IBAction func stevensonCoffeeHouse(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/pdf/stevenson-coffee-house-menu.pdf"
}
#IBAction func terraFresca(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/terra-fresca/pdf/terra-fresca-menu.pdf"
}
#IBAction func vivas(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/pdf/vivas-menu.pdf"
}
#IBAction func dismiss(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
guard let destination = segue.destination as? CafesMenu else { return }
destination.detailURL = urlToPass
urlToPass = nil
}
}
In the second one:
import UIKit
import WebKit
class CafesMenu: UIViewController {
#IBOutlet weak var webView: WKWebView!
var detailURL: String?
override func viewDidLoad() {
super.viewDidLoad()
print("URL Requested: \(detailURL)")
}
override func viewWillAppear(_ animated: Bool) {
let url = URL(string: detailURL!)
let request = URLRequest(url: url!)
webView.load(request)
}
#IBAction func dismiss(_ sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: nil)
}
}
What you need to do is use prepareForSegue:sender: to set a property in your destination view controller. prepareForSegue:sender: will be called before your initial view controller segues to any destination view controller. Within this function, we can check which button was pressed and set the appropriate URL in the destination view controller accordingly.
This approach will allow you to use any segue between your buttons and your destination view controller. This means, you simply have to drag the blue line from the buttons to the view controller you want to segue to.
1. Within your storyboard, create a segue between your first view controller and your destination view controller. This is done by holding control, clicking on the first view controller in the interface builder, and dragging over the destination view controller. Then choose a segue type:
Now, select this segue and give it the Identifier "InitialVCToDestinationVC" in the attributes inspector:
2. Make a property called urlToPass of type URL in your initial view controller:
class InitialViewController: UIViewController {
var urlToPass: URL!
#IBAction func googleButtonPressed(_ sender: Any) {
}
#IBAction func facebookButtonPressed(_ sender: Any) {
}
}
3. Make a property called receivedUrl in the destination view controller:
class DestinationViewController: UIViewController {
var receivedUrl: URL!
#IBOutlet var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let request = URLRequest(url: receivedUrl)
webView.load(request)
}
}
4. Set the urlToPass depending on which button is pressed and use the prepareForSegue:sender: function to set the destination view controller's url accordingly. Then, make use of performSegue(withIdentifier:sender:) to perform the segue with identifier InitialVCToDestinationVC.
class InitialViewController: UIViewController {
var urlToPass: URL!
#IBAction func googleButtonPressed(_ sender: Any) {
urlToPass = URL(string: "www.google.com")
performSegue(withIdentifier: "InitialVCToDestinationVC", sender: nil)
}
#IBAction func facebookButtonPressed(_ sender: Any) {
urlToPass = URL(string: "www.facebook.com")
performSegue(withIdentifier: "InitialVCToDestinationVC", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
guard let destination = segue.destination as? DestinationViewController else { return }
destination.receivedUrl = urlToPass
urlToPass = nil
}
}
5. (optional) Make use of the shouldPerformSegueWithIdentifier:sender: method within InitialViewController and check whether or not urlToPass is valid. If urlToPass is valid, perform the segue, else present an alert.
class InitialViewController: UIViewController {
...
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if let urlToPass = urlToPass {
// check if your application can open the NSURL instance
if !UIApplication.shared.canOpenURL(urlToPass) {
let alertController = UIAlertController(title: "Cannot open URL.", message: "This is an invalid URL.", preferredStyle: .alert)
let ok = UIAlertAction(title: "Okay", style: .cancel, handler: nil)
alertController.addAction(ok)
present(alertController, animated: true, completion: nil)
}
return UIApplication.shared.canOpenURL(urlToPass)
}
return false
}
}
End result:
Here's a link to the Xcode project I made the above gif from: https://github.com/ChopinDavid/PrepareForSegue
Try using the following code snippet to pass the urlParameter to second viewcontroller
class FirstViewController: UIViewController{
func googleActionButton() {
let vc = SecondViewController()
vc.urlToOpen = "www.google.com"
self.present(vc, animated: true, completion: nil)
}
func facebookActionButton() {
let vc = SecondViewController()
vc.urlToOpen = "www.facebook.com"
self.present(vc, animated: true, completion: nil)
}
}
class SecondViewController: UIViewController{
var urlToOpen = String()
override func viewDidLoad() {
super.viewDidLoad()
// set webview url to the 'urlToOpen' which you received from FirstViewController
}
}
First of all, create an enum WebURL with all the url cases that you want to open, i.e.
enum WebURL {
case google
case facebook
var url: String {
switch self {
case .google:
return "https://www.google.com"
case .facebook:
return "https://www.facebook.com"
}
}
}
Next, in FirstVC, in the UIButton's #IBAction open SecondVC using the WebURL instance corresponding to that particular button, i.e.
class FirstVC: UIViewController{
#IBAction func openGoogle(_ sender: UIButton) {
self.openSecondVC(with: WebURL.google.url)
}
#IBAction func openFacebook(_ sender: UIButton) {
self.openSecondVC(with: WebURL.facebook.url)
}
func openSecondVC(with urlString: String) {
if let vc = self.storyboard?.instantiateViewController(withIdentifier: "SecondVC") as? SecondVC {
vc.urlString = urlString
self.present(vc, animated: true, completion: nil)
}
}
}
Then, use urlString in SecondVC to configure your webView, i.e.
class SecondVC: UIViewController {
var urlString: String?
override func viewDidLoad() {
super.viewDidLoad()
//Setup your webView using urlString here...
}
}

Attempting to pass data from one viewcontroller to another using segues

I have two viewcontrollers setup and set the segue connections as well. I'm attempting to pass data from one of the VC's to the other. Using the below code and using the func override works. What i want to do is only have the override func prepare fire off when a button is pressed and when i paste the override func code into a button action, it doesnt work - the label on the first VC doesnt update - it stays to the default value i set.
First ViewController code:
var testLabel1:String = "default"
#IBOutlet weak var testLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
testLabel?.text = testLabel1
// Do any additional setup after loading the view.
}
Second ViewController code:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.destination is ViewController
{
let vc = segue.destination as? ViewController
vc?.testLabel1 = "Success"
}
}
Button action that ive tried
#IBAction func actionBtn(_ sender: Any) {
func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.destination is ViewController
{
let vc = segue.destination as? ViewController
vc?.testLabel1 = "Success"
}
}
}
You need to trigger it with performSegue
class FirstVc:UIViewController {
#IBOutlet weak var lbl:UILabel!
#IBAction func goToSecond(_ sender: Any) {
self.performSegue(withIdentifier:"YourSegueName",sender:nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "YourSegueName" {
let vc = segue.destination as! SecondVC
vc.testLabel1 = "Success"
}
}
func setData(_ str:String){
self.lbl.text = str
}
}
class SecondVC:UIViewController {
var testLabel1 = ""
weak var delegate:FirstVc?
func goBack() {
self.delegate?.setData("FromSecond")
self.dismiss(animated: true, completion: nil)
}
}

Value not passing between viewControllers

Struggling to get my viewControllers to send value from the main viewController to a second. I want it to happen on a button click, I'm going to get the value from the button and pass it to the new form. But it just isn't working.
Code for main ViewController
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func butClick(_ sender: UIButton) {
NSLog("Button Pressed : %#",[sender .currentTitle])
//var tt = [sender .currentTitle]
// Create the view controller
let vc = TimesTablesViewController(nibName: "TimesTablesViewController", bundle: nil)
vc.passedValue = "xx"
self.performSegue(withIdentifier: "pushSegue", sender: nil)
}
}
Code for second viewController called TimesTablesViewController:
class TimesTablesViewController: UIViewController {
#IBOutlet weak var titleLabel: UILabel!
var passedValue:String = ""
override func viewDidLoad() {
super.viewDidLoad()
titleLabel?.text = "\(passedValue) Times Table"
}
}
I've followed tutorials but can't seem to solve the problem! Thanks for any help!
Replace
self.performSegue(withIdentifier: "pushSegue", sender: nil)
with
self.present(vc,animated:true,completion:nil)
or ( if the current vc is inside a naigation )
self.navigationController?.pushViewController(vc,animated:true)
Using
self.performSegue(withIdentifier: "pushSegue", sender: nil)
is fit with storyboards not xibs and if this your case then you need to use the above line only inside the button action with implementing this method inside the source vc
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "pushSegue" {
if let nextViewController = segue.destination as? TimesTablesViewController{
nextViewController.passedValue = "xx"
}
}
}
I’m assuming that the new view controller is appearing, but you’re simply not seeing the data. If so, you’re evidently using storyboards. The TimesTablesViewController(nibName:bundle:) only works if you’re using XIB/NIBs and manually presenting new view controller.
If you’re really using storyboards, simplify your butClick method:
#IBAction func butClick(_ sender: UIButton) {
NSLog("Button Pressed")
performSegue(withIdentifier: "pushSegue", sender: self)
}
But implement prepare(for:sender:):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? TimesTablesViewController {
destination.passedValue = "xx"
}
}
Assuming the above fixes your problem, I might suggest a further simplification. Notably, if your butClick(_:) method is really only calling performSegue, you can segue to this next scene without any #IBAction method at all:
remove butClick(_:) entirely;
remove the connection between the button and the butClick method in IB, on the “Connections Inspector” tab in the right panel; and
control-drag from the button previously hooked up to butClick(_:) to the scene for TimesTablesViewController.
That will simplify your code further.

Swiching between 2 diferent NSViewControllers with data

I'm absolute newbie in Swift and OSX development, and I'm sorry if my question will be too noob. I want to understand principles of navigation between NSViewControllers.
I have my default ViewController, where are login and password fields and button to login. After click on button, returns token. And now I trying to change "view" to SecondViewController and save somewhere token, I will need it in future. How can I do it? and it possible to do this in function?:
#IBAction func loginButton(_ sender: Any) {
....
}
Thank you!
You need to use segues to perform this action.
First make the segues connections between the ViewControllers using to storyboard editor. After that you need to give the segues an identifier on the storyboard's attributes inspector. Then in your code you can call the new ViewController by the segue like the code below.
With this code you can pass the data using the button:
class ViewController: NSViewController {
var dataToPass: String = "DataToPass"
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func loginButton(_ sender: Any) {
performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "segueIdentifier"), sender: self)
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
if segue.identifier!.rawValue == "segueIdentifier" {
let destinationViewController = segue.destinationController as! ViewController2
destinationViewController.dataToReceive = dataToPass
}
}
}
class ViewController2: NSViewController {
var dataToReceive: String
override func viewDidLoad() {
super.viewDidLoad()
}
}
And with this code you will use the override viewWillAppear
class ViewController: NSViewController {
var dataToPass: String = "DataToPass"
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear() {
performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "segueIdentifier"), sender: self)
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
if segue.identifier!.rawValue == "segueIdentifier" {
let destinationViewController = segue.destinationController as! ViewController2
destinationViewController.dataToReceive = dataToPass
}
}
}
class ViewController2: NSViewController {
var dataToReceive: String
override func viewDidLoad() {
super.viewDidLoad()
}
}
In both cases you need to assure the data you want to pass to the other view controller is not null.

How to hide and show label when navigation VC1 to VC2 back and forth

Say, I have a label show : Loading...
problem: When return from VC(2). The label is not hidden.
How to hide it when return from VC(2) and dont hide it when in navigating to VC(2) and show the message : Loading....
in VC(1)
#IBOutlet weak var lbLoadingMsg
In viewDidLoad() {
lbLoadingMsg.hidden = true
}
-2-- turn it on when prepare to navigate to VC(2)
override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool
{
--code--
lbLoadingMsg.hidden = false
}
Override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!){
}
You can use NSNotificationCenter for that.
Follow this simple steps:
1.In your VC(2) add this code into your button from where you are going back:
#IBAction func goBack(sender: AnyObject) {
NSNotificationCenter.defaultCenter().postNotificationName("hide", object: nil)
self.dismissViewControllerAnimated(true, completion: nil)
}
2.In your First View add this code into viewDidLoad method:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "hideLabel:", name:"hide", object: nil)
}
now this method will call this function:
func hideLabel(notification: NSNotification){
self.lbLoadingMsg.hidden = true
}
And this will hide your label in first view when ever goBack button will pressed from first view.
Hope this will help you.
Write this in VC2
,
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var identifier = segue.identifier
if(identifier! == "yourIdentifier"){
var vc1:VC1 = segue.destinationViewController as! VC1
vc1.lbLoadingMsg.hidden = true
}
}
func viewDidAppear(_ animated: Bool) {
lbLoadingMsg.hidden = true
}
Move
lbLoadingMsg.hidden = true
line from viewDidLoad to viewDidAppear. I think most quicker way.