how to execute function after the view is loaded swift4 - ios

I am trying to execute a function after the view has appeared.
I have tried series of steps I tried wait()
override func viewDidLoad()
{
super.viewDidLoad()
let w = UnsafeMutablePointer<Int32>.allocate(capacity: 20)
self.title = "Quiz Section"
wait(w)
Function()
}
I tried sleep()
override func viewDidLoad()
{
super.viewDidLoad()
sleep(10)
Function()
}
I even tried viewWillAppear but none of them seemed to work. I want that once the view is in front then the function executes. Any help?

You can try viewDidAppear
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
function() // don't start function name with capital
}
OR dispatch the function in after queue if you need more duration
override func viewDidLoad()
{
super.viewDidLoad()
let w = UnsafeMutablePointer<Int32>.allocate(capacity: 20)
self.title = "Quiz Section"
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0 ) {
function()
}
}

Try this:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
function()
}

Related

Enabling a disabled tab

I have a UITabBar containing 5 tabs. I disabled one of the tabs like this:
tabBar.items?[3].isEnabled = false
To enable it again, I am using the following code:
tabBar.items?[3].isEnabled = true
The problem is that it doesn't actually get enabled again. I also tried to place the above code inside viewWillAppear and viewDidAppear, but the tab stays disabled.
Here's the full code:
import UIKit
class MainTabViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
tabBar.items?[0].title = NSLocalizedString("tab1", comment: "-")
tabBar.items?[1].title = NSLocalizedString("tab2", comment: "-")
tabBar.items?[2].title = NSLocalizedString("tab3", comment: "-")
tabBar.items?[3].title = NSLocalizedString("tab4", comment: "-")
tabBar.items?[4].title = NSLocalizedString("tab5", comment: "-")
self.tabBar.items?[3].isEnabled = true
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
}
It should be the tabBar property of the UITabBarController.
self.tabBarController?.tabBar.items?[3].isEnabled = false
If you call it from inside the custom UITabBarController subclass:
self.tabBar.items?[3].isEnabled = false
Make sure viewWillAppear and viewDidAppear of the custom UITabBarController subclass are called only once, unlike the methods in every tab, since they are called every time the tab is selected.
The below code seems to work fine:
self.tabBar.items?[3].isEnabled = false
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.tabBar.items?[3].isEnabled = true
}

Large UINavigationBar resize smoothly when popping back too rootViewController

hey guys I've used large UINavigationBar in a child ViewController and i want to resize my navBar to default size when popping back to rootViewController smoothly.
vc's gif:https://giphy.com/gifs/1P0HwqlIqqMnzibxbH
EDIT
I don't want to remove largeNavBar from parent vc, i only want to disappear it gradually and with animation like app store:https://giphy.com/gifs/YXsTA6I5r0lGik1gC8
here is the child vc code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.initUI()
super.enableLargeNavigationTitle(title: (self.favorty?.sellerProduct?.product?.name)!)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
super.removeTitleImage()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(true)
}
here is the enableLargeNavigationBar function:
func enableLargeNavigationTitle(title: String) {
self.navigationController?.view.backgroundColor = VVUtility.splashBackGroundColor()
self.navigationItem.title = "\(title)".localized()
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: -2.0)]
if #available(iOS 11.0, *) {
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationBar.backgroundColor = VVUtility.splashBackGroundColor()
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white, NSAttributedStringKey.font : VVUtility.normalFontWithPlusSize(increaseSize: 0.0)]
} else {
// Fallback on earlier versions
}
}
disableLargeNavigation function:
func disableLargeNavigationTitle() {
if #available(iOS 11.0, *) {
self.navigationController?.navigationItem.largeTitleDisplayMode = .never
self.navigationController?.navigationBar.prefersLargeTitles = false
} else {
// Fallback on earlier versions
}
}
here is parent vc code:
override func viewDidLoad() {
super.viewDidLoad()
self.initUI()
self.getData()
super.disableLargeNavigationTitle()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.addSubview(searchBarBoxView)
self.timerDelegate?.startTimer()
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.searchBarBoxView.removeFromSuperview()
self.timerDelegate?.stopTimer()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.tabBarController?.delegate = self
super.disableLargeNavigationTitle()
}
This worked for me. Try putting this code in awakeFromNib() for each view controller, with the settings changed as you need.
override func awakeFromNib() {
// Large titles
if #available(iOS 11.0, *) {
navigationController?.navigationBar.prefersLargeTitles = false // This could be true for other view controller
navigationItem.largeTitleDisplayMode = .never // This could be .always for other view controller
navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black] // Or whatever you want
} else {
// Handle iOS 10 and below (no large titles)
}
}
Alternatively, I think you can do this just in Storyboard, but that didn’t work for me.

Why are viewDidLayoutSubviews and viewWillLayoutSubviews called two times?

import UIKit
class ViewController: UIViewController {
// MARK: -property
// lazy var testBtn: UIButton! = {
// var btn: UIButton = UIButton()
// btn.backgroundColor = UIColor.red
// print("testBtn lazy")
// return btn
// }()
// MARK: -life cycle
override func viewDidLoad() {
super.viewDidLoad()
print("View has loaded")
// set the superView backgroudColor
// self.view.backgroundColor = UIColor.blue
// add testBtn to the superView
// self.view.addSubview(self.testBtn)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("View will appear")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("View has appeared")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("View will disappear")
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
print("View has desappeared")
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
print("SubViews will layout")
// layout subViews
// 'CGRectMake' is unavailable in Swift
// self.testBtn.frame = CGRectMake(100, 100, 100, 100)
// self.testBtn.frame = CGRect(x: 100, y: 100, width: 100, height: 100) // CGFloat, Double, Int
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("SubViews has layouted")
// let testBtn_Width = self.testBtn.frame.width
// print("testBtn's width is \(testBtn_Width)")
}
}
The result:
View has loaded
View will appear
SubViews will layout
SubViews has layouted
SubViews will layout
SubViews has layouted
View has appeared
As you see, I have created a new project and type some simple code.
I didn't change the size of the viewController's view.
Why are "SubViews has layouted" and "SubViews will layout" console two times?
Why are viewDidLayoutSubviews and viewWillLayoutSubviews called two times?
Because whenever setNeedsLayout or setNeedsDisplayInRect is being called internally, LayoutSubviews is also being called (once per run loop) on any given view. This applies for example if the view has been added, scrolled, resized, reused etc.

SubView(nib) wont remove after calling removeFromSuperView()

I have an overlay view to segregate content, I'm checking for authentication in viewWillAppear() and I have a Notification subscribed to my Auth method. If I authenticate before any of my other views appear the overlay does not show up, however it does on the first view and will not go away even after calling removeFromSuperView().
import UIKit
import FirebaseAuth
class ProtectedViewController: UIViewController, ForceSignInBannerDelegate,
SignUpViewControllerDelegate, LoginViewControllerDelegate{
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
NotificationCenter.default.addObserver(self, selector: #selector(checkAuthentication), name: .myNotification, object: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.checkAuthentication()
}
func checkAuthentication() {
let bannerViewController = ForceSignInBanner.instanceFromNib() as! ForceSignInBanner
bannerViewController.delegate = self
if (!AuthenticationService.sharedInstance.isAuthenticated()) {
self.setView(view: bannerViewController, hidden: false)
print("Need to login")
} else if(AuthenticationService.sharedInstance.isAuthenticated()) {
self.setView(view: bannerViewController, hidden: true)
}
}
func setView(view: UIView, hidden: Bool) {
UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: { _ in
view.isHidden = hidden
if hidden {
view.removeFromSuperview()
} else {
self.view.addSubview(view)
}
}, completion: nil)
}
It's because you're trying to remove a new ForceSignInBanner each time. Ideally you should create it once and keep a reference to the ForceSignInBanner created (as an optional property of ProtectedViewController).
Then remove the ForceSignInBanner that you've stored in the property.
class ProtectedViewController: UIViewController, ForceSignInBannerDelegate {
// This lazily loads the view when the property is first used and sets the delegate.
// Ideally you wouldn't force-case the `as` but I've left it for simplicity here.
private lazy var forceSignInBannerView: ForceSignInBanner = {
let forceSignInBannerView = ForceSignInBanner.instanceFromNib() as! ForceSignInBanner
forceSignInBannerView.delegate = self
return forceSignInBannerView
}()
// ... your other code ... //
fun toggleForceSignInBannerViewVisibility(isVisible: Bool) {
if isVisible {
view.addSubview(forceSignInBannerView)
} else {
forceSignInBannerView.removeFromSuperview()
}
}
}

Dismiss SVProgressHUD if exiting View Controller

I have a view controller that on launch shows an SVProgressHUD as data is fetched from the server. How would I dismiss the SVProgressHUD if moving back to the previous view controller before the fetch is completed?
I have tried this:
override func viewWillDisappear(animated : Bool) {
super.viewWillDisappear(animated)
if (self.isMovingFromParentViewController()){
print("before dismiss")
SVProgressHUD.dismiss()
print("after dismiss")
}
}
I get the error: fatal error: unexpectedly found nil while unwrapping an Optional value
Here is some code from the view controller that is being navigated back to:
override func viewWillAppear(animated: Bool) {
self.navigationItem.hidesBackButton = true
}
override func viewDidLoad() {
searchRestaurants.delegate = self
loadRestaurants()
super.viewDidLoad()
// Do any additional setup after loading the view.
//navigation bar title edit
self.navigationController!.navigationBar.titleTextAttributes = [ NSFontAttributeName: UIFont(name: "Chalkboard SE", size: 17)!]
//fetch list of restaurant names from database
//set table cells to values inside array
}
override func viewDidAppear(animated: Bool) {
//SVProgressHUD.dismiss()
}
override func viewWillDisappear(animated : Bool) {
super.viewWillDisappear(animated)
if (self.isMovingFromParentViewController()){
let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
print("This is run on the background queue")
SVProgressHUD.dismiss()
})
}
}

Resources