Logout delegate not working - ios

I have an app that contains a central view controller with 3 child view controllers in a scrollview that represent sections of the app. General flow of my app goes as follows
LoginVC -> AppVC [Settings, Inbox, Email]
I currently have my logout button in my Settings view controller however the actual logout function needs to be in AppVC. I have tried implementing a delegate but cannot seem to get it working correctly
class Settings: UIViewController {
var delegate: LogoutDelegate?
#IBAction func logout(_ sender: Any) {
delegate?.logoutOfApp()
}
}
protocol LogoutDelegate: class {
func logoutOfApp()
}
----------------------------------
class AppVC: UIViewController, LogoutDelegate {
func logoutOfApp() {
print("This should be called")
//Execute logout code
}
}
Can anyone help me figure out why my delegate function isnt being called in my AppVC?
Update
This is how I set up my child view controllers in a scrollview
func setupViews() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let settingsVC = storyboard.instantiateViewController(withIdentifier: "SettingsVC")
let inboxVC = storyboard.instantiateViewController(withIdentifier: "InboxVC")
let emailVC = storyboard.instantiateViewController(withIdentifier: "EmailVC")
let viewControllers = [settingsVC, inboxVC, emailVC]
let width = scrollView.bounds.width
let height = scrollView.bounds.height
scrollView.contentSize = CGSize(width: width * 3, height: height)
var idx = 0
for vc in viewControllers {
addChildViewController(vc)
let originX = CGFloat(idx) * width
vc.view.frame = CGRect(x: originX, y: 0, width: width, height: height)
scrollView.addSubview(vc.view)
vc.didMove(toParentViewController: self)
idx += 1
}
scrollView.setContentOffset(CGPoint(x: width, y: 0), animated: false)
}
I am not sure where to set my delegate. I have tried to set it inside my for loop self.delegate = vc but always get the same error of not being able to set the delegate

The problem is that you never set the delegate, otherwise the delegate will always be nil and delegate?.logoutOfApp() won't be executed.
In AppVC, you need to do something like:
override func viewDidLoad() {
super.viewDidLoad()
settings.delegate = self
}

Related

How to navigate to another viewcontroller from UITabBar?

How to navigate to another viewcontroller from UITabBar?
I am working on UITabBarController. Who have 4 TabBar Button and I have added a large Button on middle of UITabBar. So I want to navigate to new viewController when click on large Middle Button.
Actully I have added large button here Subclassing UITabBar(). I am giving you all code of UITabBar()
So Please tell me how can I do it. Rightnow everything is Working fine but only Navigateto new viewcontroller is Not working.
import UIKit
class MainTabBar: UITabBar {
private var middleButton = UIButton()
override func awakeFromNib() {
super.awakeFromNib()
setupMiddleButton()
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if self.isHidden {
return super.hitTest(point, with: event)
}
let from = point
let to = middleButton.center
return sqrt((from.x - to.x) * (from.x - to.x) + (from.y - to.y) * (from.y - to.y)) <= 39 ? middleButton : super.hitTest(point, with: event)
}
override func layoutSubviews() {
super.layoutSubviews()
middleButton.center = CGPoint(x: UIScreen.main.bounds.width / 2, y: 0)
}
func setupMiddleButton() {
middleButton.frame.size = CGSize(width: 70, height: 70)
middleButton.backgroundColor = .blue
middleButton.layer.cornerRadius = 35
middleButton.layer.masksToBounds = true
middleButton.setTitle("+", for: .normal)
middleButton.center = CGPoint(x: UIScreen.main.bounds.width / 2, y: 0)
middleButton.addTarget(self, action: #selector(largeButtonAction), for: .touchUpInside)
addSubview(middleButton)
}
#objc func largeButtonAction(_ sender:UIButton) {
print("Write your Navigation Code here.......")
jumpToHomeVC()
}
func jumpToHomeVC(){
let story = UIStoryboard(name: "Main", bundle:nil)
let vc = story.instantiateViewController(withIdentifier: "HomeVC") as! HomeVC
let nav = UINavigationController(rootViewController: vc)
nav.navigationController?.pushViewController(vc, animated: true)
}
}
I subclassed my UITabBar() to my custom MainTabBar().
I want when I click on Large button go to new UIViewController and When click on Back again Come to UITabBarController means on Dismiss or PopViewController.
Or If is there any other solution to create a large button on middle of UItabBarController. click on anywhere in button to jump to new ViewController and on dismiss come back to previous controller.

How to change label text of a label in a popover view controller when pressing a button in the main view?

I'm relatively new to Swift. I have a main view controller, ViewControllerMain, and a popover view controller, PopUpVC, which only has a label. I have a function, infoClicked that displays the popover with another function (showPopover) when the info button is clicked. When I click the button, I want to change the label text of the popover. However, with the current code, the label always displays "Default".
Here is my code:
class ViewControllerMain: UIViewController, UIPopoverPresentationControllerDelegate, GetTimesUsed {
let tipController: PopUpVC = PopUpVC().self
#IBAction func infoClicked(_ sender: UIButton) {
tipController.tipText = "Success"
showPopover()
}
func showPopover() {
let myViewController = storyboard?.instantiateViewController(withIdentifier: "popupController")
myViewController?.preferredContentSize = CGSize(width: 350, height: 200)
myViewController?.modalPresentationStyle = .popover
let popOver = myViewController?.popoverPresentationController
popOver?.delegate = self
UIView.animate(withDuration: 1, animations: {
self.GifView.alpha = 0.7
})
DispatchQueue.main.asyncAfter(deadline: .now() + 0.45) {
UIView.animate(withDuration: 0.5, animations: {
self.present(myViewController!, animated: true, completion: nil)
})
}
popOver?.permittedArrowDirections = .down
popOver?.sourceView = self.view
var passthroughViews: [AnyObject]?
passthroughViews = [infoButton]
myViewController?.popoverPresentationController?.passthroughViews = (NSMutableArray(array: passthroughViews!) as! [UIView])
popOver?.sourceRect = infoButton.frame
}
}
class PopUpVC: UIViewController {
#IBOutlet weak var tip: UILabel!
var tipText: String = "Default"
override func viewDidLoad() {
super.viewDidLoad()
tip.text = tipText
// Do any additional setup after loading the view.
}
}
Thank you for your help.
As mentioned in comments, you seem to be instantiating the popup controller 2 times, so try it like this in your showPopOver code:
let myViewController = storyboard?.instantiateViewController(withIdentifier: "popupController") as! PopUpVC
myViewController.preferredContentSize = CGSize(width: 350, height: 200)
myViewController.modalPresentationStyle = .popover
myViewController.tipText = '' //set to what ever

Display overlay view between ViewControllers

I am trying to display an overlay view on top of every ViewController after successfully logging in to show loading status of the app and load some data while this view is being displayed.
This view comes from a custom NIB file.
I display the OverlayLoadingView after a successful login request to the server, then I want to present a new ViewController on another Storyboard using:
self.present(vc, animated: true, completion: nil)
And finally hide the OverlayLoadingView in the next ViewController (This is why I handle it as a Singleton).
But when I present the next ViewController, the OverlayLoadingView disappears. Is there a way to display this loading view on top of everything while presenting a new view controller on the back at the same time?
Something like this:
LoginViewController -> Successfully logged in -> display OverlayView -> present MainViewController -> MainViewController presented below OverlayView -> Load initial data -> Hide OverlayView after initial data has been loaded.
#IBDesignable
public class OverlayLoadingView: UIView {
#IBOutlet weak var headerImageView: UIImageView!
#IBOutlet weak var detailTextLabel: UILabel!
class var sharedInstance: OverlayLoadingView {
struct Static {
static let instance: OverlayLoadingView = OverlayLoadingView(frame: UIScreen.main.bounds)
}
return Static.instance
}
// Custom view from the XIB file
fileprivate var view: UIView!
// Set header image directly by giving a value to headerImageURL variable from server response
/**
Initialiser method
*/
override init(frame: CGRect) {
super.init(frame: frame)
setupNib()
}
/**
Initialiser method
*/
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupNib()
}
fileprivate func loadNib() -> UIView? {
return Bundle.main.loadNibNamed("OverlayLoadingView", owner: self, options: nil)?.first as? UIView
}
func setupNib() {
if let overlayLoadingView = loadNib() {
self.view = overlayLoadingView
let screenWidth = Util.screenSize().width
let screenHeight = Util.screenSize().height
self.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)
view.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)
self.addSubview(view)
}
}
public func showOverlay() {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate,
let window = appDelegate.window {
self.alpha = 1.0
window.addSubview(self)
activityIndicator.startAnimating()
}
}
public func hideOverlayView() {
activityIndicator.stopAnimating()
self.removeFromSuperview()
}
}
EDIT:
To display the overlay view I am using:
DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "TabMenu", bundle: nil)
let vc = storyboard.instantiateInitialViewController()!
OverlayLoadingView.sharedInstance.showOverlay()
self.present(vc, animated: true, completion: {
// Dismiss current VC?
})
}
The views hierarchy is shown like the following image. The overlay view should be over everything.
If your requirement is to display the loading view above all controllers you can add the view to the window.
if let window = UIApplication.shared.keyWindow {
let overlay = OverlayLoadingView(frame:UIScreen.main.bounds)
overlay.tag = 1001
window.addSubView(overlay)
// remove it like this
window.viewWithTag(overlay.tag)?.removeFromSuperView()
}
By the way this is not a Singleton as I'm able to use init and create another instance mark the init as private. Make the class final to avoid reflection and replace class with static As class can be overided but static can't.

Calling method from a specific childViewControllers class

Alright, hope I can explain this as clearly as possible.
I have a Parent ViewController which has a ContainerView, this will contain different viewControllers/Class. I'm changing the content of this container at runtime like this:
let newController = (storyboard?.instantiateViewController(withIdentifier: classIdentifierFromStoryboard))! as UIViewController
let oldController = childViewControllers.last! as UIViewController
oldController.willMove(toParentViewController: nil)
addChildViewController(newController)
newController.view.frame = oldController.view.frame
transition(from: oldController, to: newController, duration: 0, options: .transitionCrossDissolve, animations:{ () -> Void in
}, completion: { (finished) -> Void in
})
oldController.removeFromParentViewController()
newController.didMove(toParentViewController: self)
So for example, the current controller that shows on UI is firstVC, which kinda look like
class firstVC {
func removeAnnotations() {
//something that removes annotation from MapVC
}
}
On a certain event on the parent controller, how can I access the instance of firstVC so that i'll be able to call removeAnnotations? As of the moment I am getting nil, using this on parent controller firstVC.removeAnnotations, assumably this calls another instance of the class. Any help would be great! Hope my explanation makes sense. Thanks!
You could run down the child view controllers like this:
for case let vc as firstVC in self.childViewControllers {
vc.removeAnnotations()
}
This will run down all the child view controllers that are of type firstVC and execute the removeAnnotations method
in this code is child view controller ProfileViewController
in first create one object of child view controller like this
var objectProfile:ProfileViewController!
then viewDidLoad method
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
objectProfile = storyboard.instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileViewController
objectProfile.view.frame = CGRect(x: -(self.view.frame.size.width - 40), y: 0, width: self.view.frame.size.width - 40, height: self.view.frame.size.height)
self.view.addSubview(objectProfile.view)
self.navigationController?.didMove(toParentViewController: objectProfile)
objectProfile.view.isHidden = true
}
then button click method code here
#IBAction func btnProfilePressed(_ sender: UIButton) {
UIView.animate(withDuration: 0.3) {
self.objectProfile.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width - 40, height: self.view.frame.size.height)
}
}
then touchesBegan
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
objectProfile.view.isHidden = false
UIView.animate(withDuration: 0.3) {
self.objectProfile.view.frame = CGRect(x: -(self.view.frame.size.width - 40), y: 0, width: self.view.frame.size.width - 40, height: self.view.frame.size.height)
}
}
complete set this code out put is

How to create a custom pop up view with swift?

So I am working on a simple app, where I use a table view. This table view displays the name of "players". But in order for me to add players in the table view, I want a pop up window to be displayed with a text field where you provide the name.
Now I have been reading about creating a xib or nib file, but I am not sure how to "load" the pop up window.
What's the best approach to this?
Looks like this:
In storyboard
In storyboard create one UIViewController and design it according to your requirement.
Set custom class as anotherViewController and Storyboard_ID as another_view_sid
Create one new Cocoa Touch Class as anotherViewController and subclass of UIVIewController
In viewController
let popvc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "another_view_sid") as! anotherViewController
self.addChildViewController(popvc)
popvc.view.frame = self.view.frame
self.view.addSubview(popvc.view)
popvc.didMove(toParentViewController: self)
In anotherViewController
override func viewDidLoad() {
super.viewDidLoad()
showAnimate()
}
}
#IBAction func Close_popupView(_ sender: Any) {
removeAnimate()
}
func showAnimate()
{
self.view.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.view.alpha = 0.0
UIView.animate(withDuration: 0.25, animations: {
self.view.alpha = 1.0
self.view.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
})
}
func removeAnimate()
{
UIView.animate(withDuration: 0.25, animations: {
self.view.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.view.alpha = 0.0
}, completion: {(finished : Bool) in
if(finished)
{
self.willMove(toParentViewController: nil)
self.view.removeFromSuperview()
self.removeFromParentViewController()
}
})
}
you'd create an custom UIView with all respected object needed, from your Controller's viewDidLoad() you'll hide it.
customView.hidden = true
Whenever your user wants to perform some action or task, you unhide it and once the user finished then hide it again or remove from the superView.
customView.hidden = false
Below there is some code to help you start
private var customView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
customView.hidden = true
}
private func loadCustomViewIntoController() {
let customViewFrame = CGRect(x: 0, y: 0, witdh: view.frame.width, height: view.frame.height - 200)
customView = UIView(frame: customViewFrame)
view.addSubview(customView)
customView.hidden = false
// any other objects should be tied to this view as superView
// for example adding this okayButton
let okayButtonFrame = CGRect(x: 40, y: 100, width: 50, height: 50)
let okayButton = UIButton(frame: okayButtonFrame )
// here we are adding the button its superView
customView.addSubview(okayButton)
okayButton.addTarget(self, action: #selector(self.didPressButtonFromCustomView:), forControlEvents:.TouchUpInside)
}
func didPressButtonFromCustomView(sender:UIButton) {
// do whatever you want
// make view disappears again, or remove from its superview
}
#IBAction func rateButton(sender:UIBarButtonItem) {
// this barButton is located at the top of your tableview navigation bar
// when it pressed make sure you remove any other activities that were on the screen, for example dismiss a keyboard
loadCustomViewIntoController()
}
Check it out this github project, It's closed to be production ready, it gives you a better way to deal (present and dismiss) with UIViews
If you only want the player's name then use a UIAlertController containing a textfield
This 3rd party EzPopup (https://github.com/huynguyencong/EzPopup) can help you show it up. Just design your popup in storyboard, then init it.
// init YourViewController
let contentVC = ...
// Init popup view controller with content is your content view controller
let popupVC = PopupViewController(contentController: contentVC, popupWidth: 100, popupHeight: 200)
// show it by call present(_ , animated:) method from a current UIViewController
present(popupVC, animated: true)

Resources