How reload viewcontraller like first time in Swift 4?
Details: when run app then enter viewcontraller then exit from it and I want back to same viewcontraller I want download viewcontraller from new same first time.
//code close viewcontraller :
self.dismiss(animated: true, completion: {})
//code on enter or back to viewcontraller :
DispatchQueue.main.async {
self.performSegue(withIdentifier: "sbmpo2", sender: nil)
}
Assign data to the ViewController or making API calls inside viewWillAppear that will call everytime when you came to that viewcontroller. Only you have to do to call data population functions/API call inside viewWillAppear
override func viewWillAppear(_: Bool) {
super.viewWillAppear(true)
//call your data populating/API calls from here
}
Hope this will help you
Take a look at the following methods of UIViewController:
viewWillAppear(_:)
viewDidAppear(_:)
viewWillDisappear(_:)
viewDidDisappear(_:)
The first two are called each time the view is shown. The last two are called each time the view goes away.
You can override these methods in your ViewController to setup your view as you wish.
self.dismiss(animated: true) {
//UIViewController is dismissed
DispatchQueue.main.async
self.performSegue(withIdentifier: "sbmpo2", sender: nil)
}
}
Hope this will help you
Related
I'd like to detect a modal dismissal in the view controller that's presenting the modal.
This method works amazing for detecting the new iOS 13 swipe dismissal on the new card modals:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MyIdentifier" {
segue.destination.presentationController?.delegate = self
}
}
extension MyController: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
//clean up UI (de-selecting stuff) once modal has been dismissed
}
}
However, presentationControllerDidDismiss is NOT called if the modal dismisses itself programmatically through an action:
#IBAction func btnDismissTap(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
Is this a bug or is there a way I can programmatically call whatever the "swipe" dismiss is so I can detect all dismissals the same way? Currently I'm writing extra "dismiss" delegate methods into my modals as a work around and it seems unnecessary.
However, presentationControllerDidDismiss is NOT called if the modal dismisses itself programmatically through an action
self.dismiss(animated: true, completion: nil)
It doesn’t need to be called, because you dismissed the modal yourself, in code. You cannot not know that the modal was dismissed. You don’t need to receive a dismissal signal, because you gave the dismissal signal in the first place.
You typically don’t get a delegate method call reporting something your own code did. Delegate methods report user actions. It would be crazy if everything you yourself did in code came back as a delegate method call.
Mojtaba Hosseini, answer is something I was looking for.
Currently, I need to write a delegate function to let the presenting view know that the user dismissed the modal PLUS do the presentationControllerDidDismiss handler for swipe dismissals:
#IBAction func btnDismissTap(_ sender: Any) {
self.dismiss(animated: true, completion: {
self.delegate?.myModalViewDidDismiss()
})
}
I wanted to handle both of these the same way and Mojtaba's answer works for me. However, presentationControllerDidDismiss does not get invoked if you call it inside of the self.dismiss completion block, you need to call it before.
I adapted my code to use "presentationControllerWillDismiss" (for clarity) and simply called the delegate before I dismiss programmatically in my modals and it works great.
#IBAction func btnDismissTap(_ sender: Any) {
if let pvc = self.presentationController {
pvc.delegate?.presentationControllerWillDismiss?(pvc)
}
self.dismiss(animated: true, completion: nil)
}
Now, I no longer need to create delegate functions to handle modal dismissals in code and my swipe handler takes care of all scenarios.
FYI, what I'm "handling" is doing some UI clean up (de-selections, etc) on the presenting UI once the modal is dismissed.
As #matt mentioned, there is no need to inform the one who dismissed a view by delegate. Because it is already known. BUT if you need that delegate method to be called, you should call it manually your self after dismissing the view:
#IBAction func btnDismissTap(_ sender: Any) {
self.dismiss(animated: true) {
presentationController?.delegate?.presentationControllerDidDismiss?(presentationController!)
}
}
I am making a game, where I go from the main screen to a ArcadeViewController, which loads up the SKScene, and save the previous VC as prevVC.
I use segues created in storyboard to move between VC.
The problem is that each time I move to a VC, instead of moving into the old one, a copy gets created, and both of them start to run at the same time.
I tried removing them by running the following codes, when I move into the VC:
override func viewDidAppear(_ animated: Bool) {
UIApplication.shared.keyWindow?.rootViewController = self
self.view.window?.rootViewController?.dismiss(animated: true, completion: nil)
prevVC.reloadViewFromnib()
prevVC.dismiss(animated: false, completion: nil)
UserDefaults.standard.set(0, forKey: "since_The_Last_Ad")
}
extension UIViewController {
func reloadViewFromnib() {
let parent = view.superview
view.removeFromSuperview()
view = nil
parent?.addSubview(view) // This line causes the view to be reloaded
}
}
It helped to reduce the number of copies created, but still the are some.
How can I remove duplicate views?
So the solution ended up being to use the normal segue to launch the ArcadeVC from GameVC(start VC) for the first time.
Then set the ArcadeVC as rootVC:
UIApplication.shared.keyWindow?.rootViewController = self
Then use a normal segue to go back to the GameVC.
After the ArcadeVC is set as the rootVC, just use normal segue to the ArcadeVC form GameVC, and unwind from GameVC to AracdeVC.
So i am new to app development and i am trying to set up a very simple delegation/protocol pattern. I have been searching and trying different tutorials but can't seem to find anything that works and am getting in such a muddle. Please can somebody help. I will break i down so that its really clear as to what i need -
I have two view controllers, 'DetailedVC' and 'SelectionsVC'.
DetailedVC has a variable called -
var sendingData = (choice: "", choiceValue:0.0)
and
UIbutton buttonSelectTapped
SelectionsVC has a variable called -
var recievedData = (choice: "", choiceValue:0.0)
And all i want to do is send the data from the variable 'sendingData' in DetailedVC when the button (buttonSelectTapped) is tapped to the SelectionsVC and store it in the variable 'recievedData'. I do not want the VC to transition from one to the other or anything to be sent back, only to send the data to the other VC.
Then when the user views that controller 'SelectionsVC' at whatever stage, the data will be called in the viewDidLoad when loading that controller.
Use NSUserDefault to pass data between viewcontroller if you do not want the VC to transition from one to the other or anything to be sent back, only to send the data to the other VC.
DetailedVC Code
func viewDidLoad() {
NSUserDefaults.standardUserDefaults().removeObjectForKey("selectedData")
}
func didTapButtonSelectTapped() {
NSUserDefaults.standardUserDefaults().setDouble(sendingData , forKey: "selectedData")
}
SelectionsVC code
func viewDidLoad() {
if(NSUserDefaults.standardUserDefaults().doubleForKey("selectedData")) {
recievedData = NSUserDefaults.standardUserDefaults().doubleForKey("selectedData")
}
}
But as your question title describe their is no use of protocol/delegate in above code.
Passing Data on transition from viewcontroller :
DetailedVC Code
func didTapButtonSelectTapped() {
let vc = SelectionsVC()
vc.recievedData = sendingData
self.presentViewController(vc, animated: true, completion: nil)
}
I want to open an other view controller, after checking if it is the first run of the app.
It works when I press a button but not when I call the method openMap
class TutorialController: UIViewController {
override func viewDidLoad() {
//check if the app opens for the first time
if(UserDefaults.standard.bool(forKey: "HasLaunchedOnce"))
{
// app already launched
print("not first launch")
openMap()
}
else
{
// This is the first launch ever
UserDefaults.standard.set(true, forKey: "HasLaunchedOnce")
UserDefaults.standard.synchronize()
print("first launch")
openTutorial()
}
}
func openTutorial(){
}
#IBAction func openMap(){
print("openmap opened")
performSegue(withIdentifier: "openMap", sender: nil)
}
}
I assume, you've connected your button to #IBAction func openMap()
if so, you should not call openMap() action inside your viewDidLoad, but use the same code performSegue(withIdentifier: "openMap", sender: nil) instead in your viewDidAppear:
if(UserDefaults.standard.bool(forKey: "HasLaunchedOnce"))
{
// app already launched
print("not first launch")
performSegue(withIdentifier: "openMap", sender: nil)
}
...
If it doesn't work, you've probably made a mistake with creation of your segue and have connected Button to the destination ViewController directly in your storyboard instead of connecting two controllers:
If so, just remove the old segue, and re-crete it in the way as it is on the image above and assign the same segue id "openMap"
EDITED:
Please, move performing of your segue to the viewDidAppear instead of viewDidLoad, because viewDidLoad is called when the ViewController object is created and it's not yet attached to the window.
Ok, from what I understand is that you want to perform a segue "openMap" when it HasLaunchedOnce. Well what you're doing wrong is that you're calling an #IBAction func. This is my suggestion
if you still want to have that button
create a function and name if whatever you want. Inside this function perform this segue. Link this function to the if else statement and the button.
eg:
//if else statement
if(UserDefaults.standard.bool(forKey: "HasLaunchedOnce"))
{
// app already launched
print("not first launch")
anotherFunction()
}
//#ibaction (scrap this if you don't want the button)
#IBAction func openMap()
{
print("openmap opened")
anotherFunction()
}
//another function
func anotherFunction()
{
performSegue(withIdentifier: "openMap", sender: nil)
}
hope this helps
I am working on an app where it starts out at a tableViewController which loads and displays data stored in a Realm database. I have it so I can create a new entry in my Realm database in a separate scene and the save button unwind segues back to the initial tableView.
I current have it so the tableViewController will reload the tableView on pull down (something I Learned here, second answer down) but I would be better if the tableView would reload its self automatically upon unwind, displaying all the data in my database, including my new entry. Could someone please direct me to a tutorial that will teach me how this is done.
Additional info: My app is embedded in a navigation controller. The save button is located the bottom tool bar.
You can use NSNotification for that.
First of all in your tableViewController add this in your viewDidLoad method:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshTable:", name: "refresh", object: nil)
}
And this will call one method from your class:
func refreshTable(notification: NSNotification) {
println("Received Notification")
tableView.reloadData() //reload your tableview here
}
So add this method too.
Now in your next view controller where you add new data into data base add this in you unWindSegue function:
NSNotificationCenter.defaultCenter().postNotificationName("refresh", object: nil, userInfo: nil)
Hope it will help
Try reloading your tabledata in viewWillAppear in initial (tableview)controller.
override func viewWillAppear(animated: Bool) {
self.tableView.reloadData()
}
Or call again the function through which you are loading your data from Realm like
override func viewWillAppear(animated: Bool) {
getMyData() //or whatever your function name is
}
If you are using storyboard unwind segue, try using
func unwindSegue(segue:UIStoryboardSegue) {
if segue.identifier == "identifier" {
getData()
self.tableView.reloaddata()
}
}