Swift Call Particular function from another class for Present ViewController - swift

My Scenario, I am trying to call a ViewController class file particular function from another one class file. Here, I am getting below warning and ViewController not presenting.
My Code Below ViewControllerA
func previewview(){ // Inside ViewControllerA
DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let fileViewController = storyboard.instantiateViewController(withIdentifier: "fileviewcontroller")
let navController = UINavigationController(rootViewController: fileViewController)
self.present(navController, animated: true, completion: nil)
} }
Below code In Another Class File
import UIKit
class FileController {
//MARK:- Call a file preview
ViewControllerA().self.previewview()
}
Warning: Attempt to present on
whose view is not in the window
hierarchy!

Try this
Viewcontroller().FuncName()
Example:
LoginViewController().checkLoginValidation()

Use swift's Delegate Protocol to call a function in a class from different class.
Here is a link for understanding how delegate protocol works.
https://medium.com/#nimjea/delegation-pattern-in-swift-4-2-f6aca61f4bf5

Here is how you can proceed. This is just an example. You can take the idea and implement in you code as per your requirement.
Instead of creating a separate ViewController, create a ViewModel that handles the implementation of saving the file, i.e.
class SaveOptionsViewModel {
func save(file: String, handler: (()->())?) { //add parameters to save a file as per requirement
//save the file here...
handler?()
}
}
Now, in the controller that contains multiple save options, create a property of type SaveOptionsViewModel.
And present PreviewVC from SaveOptionsVC in the handler once the file is saved using the SaveOptionsViewModel after tapping the saveButton.
class SaveOptionsVC: UIViewController {
let viewModel = SaveOptionsViewModel()
#IBAction func onTapSaveButton(_ sender: UIButton) {
self.viewModel.save(file: "") {
if let previewVC = self.storyboard?.instantiateViewController(withIdentifier: "PreviewVC") {
self.present(previewVC, animated: true, completion: nil)
}
}
}
}
Add the custom implementation of PreviewVC as per your requirement.
class PreviewVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
//add the code...
}

Related

Call other viewcontroller withount making new instance

I have a mainTabBarController and inside it a mainViewController
I have the mainTabBarController's instance in the mainViewController
The problem is that when I add a notification call for the hello() function in the mainTabBarC, then it gets called twice
mainTabBarController:
class MainTabBarController : UITabBarController {
// Main Code
override func viewDidLoad() {
print("viewDidLoad")
NotificationCenter.default.addObserver(self, selector: #selector(hello), name: "sayHello", object: nil)
}
#objc func hello(){
print("Hello")
}
}
mainViewController:
class MainViewController: UITableViewController {
// Classes
let mainTabBarController = MainTabBarController()
}
And in AppDelegate I wanna call the hello function whenever app becomes active
func applicationDidBecomeActive(_ application: UIApplication) {
NotificationCenter.default.post(name: "sayHello", object: nil)
}
Now the problem is, that I have the mainTabBarC, and inside it I have the mainViewController which contains the mainTabBarC too..
And the hello() function will be called 2x times
How can I call a MainTabBarController function from MainViewController without creating a whole new instance?
Your MainViewController already holds a reference to MainTabBarController:
You could use it in two different ways:
// Option 1
if let tabBarController = tabBarController {
// do something with your tabBarController
}
// Option 2
guard let tabBarController = tabBarController else { return }
// do something with your tabBarController
I'm not sure if I'm doing it right, but the correct code in MainViewController might be:
var mainTabBarController: MainTabBarController!
override func viewDidLoad() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
mainTabBarController = storyboard.instantiateViewController(withIdentifier: "MainTabBarController") as! MainTabBarController
}

Page View Controller viewDidLoad() Issues

I'm learning Swift/Xcode and trying to create an app with three pages that you can swipe back and forth using a Page View Controller. The issues I'm having lie in the UIViewController subclass, more specifically the viewDidLoad() function. I'm getting errors like "value of type 'NameOfMyClass' has no member datasource/delegate" and "use of unresolved identifier "setViewControllers". I've followed many tutorials and checked other posts but no one seems to be having these issues. When I attempted to run this I would get a black screen, and now I get a terminated due to signal 15 error.
Here's the relevant code where the errors are popping up:
import UIKit
class RootPageViewController: UIViewController,
UIPageViewControllerDataSource, UIPageViewControllerDelegate {
lazy var viewControllerList:[UIViewController] = {
return [self.VCInstance(name: "MissionOne"),
self.VCInstance(name: "MissionTwo"),
self.VCInstance(name: "MissionThree")]
}()
private func VCInstance(name: String) -> UIViewController {
return UIStoryboard(name: "Main", bundle:
nil).instantiateViewController(withIdentifier: name)
}
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self //...has no member 'dataSource' error
self.delegate = self //...has no member 'delegate' error
if let MissionOne = viewControllerList.first {
setViewControllers([MissionOne], direction: .forward, animated:
true, completion: nil)
//use of unresolved indentifier 'setViewControllers' error
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
The other issue I'm having, and it may be related, is that the Page View Controller is not accepting/recognizing my class file to set as the custom class in the story board.
Thanks in advance for any insight or suggestions.
your RootPageViewController is subclass of UIViewController, not a UIPageViewController
I looks to me that you are mixing two different controllers here.
What you want to do is add 3 RootPageViewController to a UIPageViewController, yet here you are trying to add 3 RootPageViewControllers to a RootPageViewController!
One way to fix it is to have a RootPageViewController and a separate UIPageViewController which will contain all RootPageViewControllers like so:
// This is a UIPageViewController containing all RootPages
class PagesViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
lazy var viewControllerList:[UIViewController] = {
return [RootPageViewController.VCInstance(name: "MissionOne"),
RootPageViewController.VCInstance(name: "MissionTwo"),
RootPageViewController.VCInstance(name: "MissionThree")]
}()
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
if let MissionOne = viewControllerList.first {
setViewControllers([MissionOne], direction: .forward, animated:
true, completion: nil)
}
}
}
And the RootPageViewController which will be added in the UIPageViewController above:
// This is a UIViewController representing a single page
class RootPageViewController: UIViewController {
static func VCInstance(name: String) -> UIViewController {
return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: name)
}
// Do what you need a page to do...
}
With such a construction you will have all your errors solved and you will also be able to use PagesViewController as custom class in your Storyboard!

Removing Data on Maps with different view controllers

I am really struggling on an issue that I think is rather interesting and quite difficult. My application lets the user create annotation locations within a Mapview. They also have the option to edit and delete these locations in another modal view controller.
The issue I am facing is that when the user presses delete, which removes the location from firebase, the annotation is still displayed upon the map. I cannot reload my annotation data within the view did appear as this does not suit my application. I cant have my annotations being reloaded every time I bring up the Mapview.
I need to figure out a way to implement an annotation reload when the delete button is pressed. However, as this happens within my delete view controller (which does not contain the mapView) I cannot use the reload function. Is there a way to connect view controllers so that I can apply the reload function when delete is pressed?
Updated Code **
This is my map view controller:
class ViewController: UIViewController, SideBarDelegate, MGLMapViewDelegate, DeleteVCDelegate {
let EditSaveSpotController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "EditVC") as! EditSaveSpotViewController
override func viewDidLoad() {
super.viewDidLoad()
EditSaveSpotController.delegate = self
}
func wholeRefresh() {
let uid = FIRAuth.auth()!.currentUser!.uid
let userLocationsRef = FIRDatabase.database().reference(withPath: "users/\(uid)/personalLocations")
userLocationsRef.observe(.value, with: { snapshot in
for item in snapshot.children {
guard let snapshot = item as? FIRDataSnapshot else { continue }
let newSkatepark = Skatepark(snapshot: snapshot)
self.skateparks.append(newSkatepark)
self.addAnnotation(park: newSkatepark)
}
})
if let annotations = mapView.annotations {
mapView.removeAnnotations(annotations)
}
for item in skateparks {
self.addAnnotation(park: item)
}
}
This is my delete view controller:
import UIKit
import Firebase
protocol DeleteVCDelegate {
func wholeRefresh()
}
class EditSaveSpotViewController: UIViewController {
var delegate: DeleteVCDelegate?
#IBAction func deleteSkateSpot(_ sender: Any) {
ref = FIRDatabase.database().reference(withPath: "users").child(Api.User.CURRENT_USER!.uid).child("personalLocations/\(parkId!)")
ref.observe(.value, with: { (snapshot) in
self.ref.setValue(nil)
self.dismiss(animated: true, completion: nil)
self.delegate?.wholeRefresh()
// self.delegate?.mainRefresh()
print("CheckWorking")
})
}
}
This is very high level and I did not have a chance to verify but it should be enough to get you going:
Modal Delete View
protocol DeleteVCDelegate {
func mainRefresh()
}
class DeleteVC: UIViewController {
var delegate: DeleteVCDelegate?
//your delete code
#IBAction func deleteSkateSpot(_ sender: Any) {
ref = FIRDatabase.database().reference(withPath: "users").child(Api.User.CURRENT_USER!.uid).child("personalLocations/\(parkId!)")
ref.observe(.value, with: { (snapshot) in
self.ref.setValue(nil)
//call to delegate
self.delegate?.mainRefresh()
})
}
}
MapView Class (implement DeleteVCDelegate)
class mapVC: MKMapViewDelegate, DeleteVCDelegate{
//when you present your DeleteVC set its delegate to the map view
let vc=(self.storyboard?.instantiateViewController(withIdentifier: "deleteVC"))! as! DeleteVC
//set the delegate
vc.delegate=self
//present deleteVC
self.present(vc, animated: true, completion:nil)
//implement delegate method of DeleteVC
func mainRefresh(){
//dismiss modal
self.dismiss(animated: true) {
//update view
self.loadLocations()
self.annotationRefresh()
}
}
}

open class UIButton trying to change view controller

So i have a UIButton with its own custom class (open class circlemenu: UIButton), the button is placed on a view controller but the code for the button is in a seperate swift file.
as the custom class produces results i would like it to change from the viewcontroller where the button is physically place to another viewcontroller.
at them moment I'm just getting an error as i can't do like i normally would from a VC item as the button has no self??:
class circlemenu {
var parentViewController:UIViewController!
func presentNewViewController() {
let newViewController = parentViewController.storyboard?.instantiateViewControllerWithIdentifier("YOUR STORYBOARD ID") as UIViewController
parentViewController.presentViewController(newViewController, animated: true, completion: nil)
}
}
i have also tried setting up a relationship with the unbutton and the viewcontroller with the following in my custom class
var parentViewController:UIViewController!
func presentNewViewController() {
let newViewController = parentViewController.storyboard?.instantiateViewControllerWithIdentifier("storyboardID") as UIViewController
parentViewController.presentViewController(newViewController, animated: true, completion: nil)
}
and this in the viewcontroller class
func myCustomClass() {
var customButton = circlemenu()
customButton.parentViewController = self
}
but it just keeps throwing me errors.

How to bring value from a UIviewController using delegate without instantiating object

I have 3 UIViewControllers say:
v1ViewController
v2ViewController
v3ViewController.
I have pushed controllers as v2 on v1 and v3 on v2.
Now I want to bring some value back to v1ViewController from v3ViewController using delegates.
On v3Viewcontroller I wrote it:
for vc in self.navigationController!.viewControllers{
if vc is v1ViewController{
delegate?.returnFilteredImage(imageView.image!)
self.navigationController?.popToViewController(vc, animated: true)
}
}
How can I use delegates because in v1ViewController I haven't create object of v3Viewcontroller; consequently I cannot connect delegate to self.
So how can i do that.
1. Using delgates
create a protocol and implement in your firstviewcontroller
protocol My {
func returnFilteredImage(image: UIImage)
}
class FirstViewController: UIViewcontroller, My {
...
func returnFilteredImage(image: UIImage) {
}
}
and in your thirdViewController create a property and assign FirstViewController delegate to this.
class ThirdViewController: UIViewController {
var delegate: My?
...
override func viewDidLoad() {
super.viewDidLoad()
for vc in self.navigationController!.viewControllers{
if vc is FirstViewController {
let vc1 = vc as! FirstViewController
self.delegate = vc1
self.delegate?.returnFilteredImage(imageView.image!)
self.navigationController?.popToViewController(vc, animated: true)
}
}
}
}
2. Using local notifications
check here
You can do this using local notifications
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//add observer
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.didgetImage(_:)), name: "receiveImageNotification", object: nil)
}
func didgetImage(notification: NSNotification) {
if let image = notification.userInfo?["image"] as? UIImage {
// do something with your image
}
}
}
and from third view controller, first notification
let imageDataDict:[String: UIImage] = ["image": image]
NSNotificationCenter.defaultCenter().postNotificationName("receiveImageNotification", object: self, userInfo: imageDataDict)
Hope this helps :)