IBAction not being called after modal transition - ios

I have the following IBActions on my navigation bar
#IBAction func logoutPressed(sender: AnyObject) {
SweetAlert().showAlert("Are you sure?", subTitle: "Do you really want to logout?", style: AlertStyle.Warning, buttonTitle:"Cancel", buttonColor:UIColorFromRGB(0xD0D0D0) , otherButtonTitle: "Yep", otherButtonColor: UIColorFromRGB(0xDD6B55)) { (isOtherButton) -> Void in
if isOtherButton == false {
let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64( Double(NSEC_PER_SEC) * 4.0 ))
SwiftSpinner.show("Logging out")
dispatch_after(popTime, dispatch_get_main_queue(), {
PFUser.logOut()
self.performSegueWithIdentifier("logoutSegue", sender: nil)
SwiftSpinner.hide()
})
}
else {
}
}
}
//OPTIONS MENU
#IBAction func optionsPressed(sender: AnyObject) {
let alert = SCLAlertView()
alert.addButton("Submit Feedback"){
var subjectText = "feedback"
var toRecipient = ["some email address"]
var mc:MFMailComposeViewController = MFMailComposeViewController()
mc.mailComposeDelegate = self
mc.setSubject(subjectText)
mc.setToRecipients(toRecipient)
self.presentViewController(mc, animated: true, completion: nil)
}
alert.addButton("About") {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("about") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
and so on....
And this works perfectly fine when I launch the app to the view controller containing these IBActions.
However, the problem is when I perform a modal/push transition into the said view controller, the IBAction's aren't being called....
Any ideas?

I just dealt with this issue too, may not be a general solution as for me it was a silly mistake, but the issue was that i had changed the class of the 'view' inside my ViewController:
The highlighted view was named something else until i changed it back to UIView in the identity inspector:
Hope that helps you, or someone else :)

Related

pushing ViewController over current ViewController from deeplink swift

I am using deeplink in my application and from the central area, I am trying push a screen in another ViewController based on my deeplink.
The issues I have is that when I cancel the pushed ViewController, the entire application stack is dismissed and I just want to pop back to the presenting viewcontroler.
func getCurrentNanvigationController() -> UINavigationController? {
//targeted UINavigationController
var navigationController: UINavigationController? = nil
if let nav = window?.rootViewController as? UINavigationController {
if let topNav = window?.topViewController()?.navigationController {
navigationController = topNav
}
else{
navigationController = nav
}
}
// Wallet Module is the stand alone module, which means its not embeded in the Navigator app
else if let tabBar = window?.rootViewController as? UITabBarController,
let nav = tabBar.selectedViewController as? UINavigationController {
navigationController = nav
}
else {
//should not happen, window root controller shouldbe be either UINavigationController or UITabBarController
}
return navigationController
}
public extension UIWindow {
func topViewController() -> UIViewController? {
var top = self.rootViewController
while true {
if let presented = top?.presentedViewController {
top = presented
} else if let nav = top as? UINavigationController {
top = nav.visibleViewController
} else if let tab = top as? UITabBarController {
top = tab.selectedViewController
} else {
break
}
}
return top
}
}
This is the currentViewController that I am trying to push another controller over from the deeplink
#objc func addNavBarItemTapped() {
let storyBoard = UIStoryboard(storyboard: .addVC, bundle: .main)
let controller = storyBoard.instantiateViewController(withIdentifier: "AddViewController")
self.navigationController?.pushViewController(controller, animated: true)
}
How can I effectively push over the AddViewController because that is the presenting ViewController and when I dismiss the presented ViewController from the navigation stack, I am not removing the entire app navigation but instead returning back to AddViewController
How the dismissal of this view controller is achieved is like this.
public extension UIViewController {
func alert(title: String,
message: String? = nil ,
attributedMessage: NSMutableAttributedString? = nil,
okAction: AlertActionButton = ("ok_button".fpxLocalizedText, .default, nil),
cancelAction: AlertActionButton = (nil, .cancel, nil),
complete: (() -> Void)? = nil) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
if let attributedMessage = attributedMessage {
alertController.setValue(attributedMessage, forKey: "attributedMessage")
}
let oKAction = UIAlertAction(title: okAction.0, style: okAction.1, handler: okAction.2)
if let cancelButtonTitle = cancelAction.0 {
let cancelAction = UIAlertAction(title: cancelButtonTitle, style: cancelAction.1, handler: cancelAction.2)
alertController.addAction(cancelAction)
}
alertController.addAction(oKAction)
self.present(alertController, animated: true, completion: complete)
}
}
In the presented Viewcontroller
public func declineButtonClicked() {
alert(title: "decline_warning_title".fpxLocalizedText,
message: "decline_warning_message".fpxLocalizedText,
okAction: ("yes_button".fpxLocalizedText, .destructive, { _ in self.sendDeclineRequest() }),
cancelAction: ("decline_cancel_button".fpxLocalizedText, .cancel, { _ in self.dismiss(animated: true, completion: nil) }))
}
Also sometimes if I have a presented Viewcontroller and need to show this ViewController, it is often presented in the background of the presented viewcontroller
In iOs push duty perform with UINavigationController
wherever you need to push so you need to UINavigationController.
You should Create another UInavigationController in Deep Link,
let storyBoard = UIStoryboard(storyboard: .addVC, bundle: .main)
let controller = storyBoard.instantiateViewController(withIdentifier: "AddViewController")
let navigationController = UINavigationController(rootViewController:controller)
self.navigationController?.present(navigationController, animated: true, completion: nil)
or
window?.getCurrentNanvigationController().present(navigationController, animated: true, completion: nil)
so now you have a new navigation controller that work stand alone.

UIActivityViewController dismissing current view controller after sharing file

UIActivityViewController dismisses the presenting view controller after sharing files.
this is happening in iOS 13+ only. Is there any permanent solution for this?
Others apps seem to have this issue too after updating to iOS 13.
class VC : UIViewController {
#IBAction func moveFiles(_ sender: UIButton) {
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: "Move", style: .default, handler: { action in
let activityController = UIActivityViewController(activityItems: urls, applicationActivities: nil)
if (UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad) {
activityController.popoverPresentationController?.sourceRect = sender.frame
activityController.popoverPresentationController?.sourceView = sender.superview
}
self.present(activityController, animated: true, completion: nil)
}))
}
}
Here is the work around for your issue.
let tempController = TransparentViewController()
tempController.modalPresentationStyle = .overFullScreen
activityViewController.completionWithItemsHandler = { [weak tempController] _, _, _, _ in
if let presentingViewController = tempController?.presentingViewController {
presentingViewController.dismiss(animated: false, completion: nil)
} else {
tempController?.dismiss(animated: false, completion: nil)
}
}
present(tempController, animated: true) { [weak tempController] in
tempController?.present(activityViewController, animated: true, completion: nil)
}
Found similar question with solution which helps me. For iOS 13 show UIActivityViewController in another UIWindow
Stackoverflow answer
Seems it's fixed in iOS 14.4
For older iOS versions I found easier workaround. Override dismiss(animated:completion:) with empty implementation so it won't be dismissing itself automatically.
However, you can still dismiss this VC using super.dismiss(animated:completion).
E.g
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
// do nothing to workaround bug - automatically dimisses this VC after saveToCameraRoll activity was performed
// call super.dismiss(animated:completion:) in order to really dismiss this VC
// seems fixed in iOS 14.4
}
...
#objc private func didTapCloseButton(_ sender: UIButton) {
super.dismiss(animated: true) // calling parent class implementation
}
I have same issue right now on iOS target 14.1.
I made my solution based on answers I found.
final class ShareViewController: UIViewController {
private let activityItems: [Any]
private let applicationActivities: [UIActivity]?
// Same looking initializer as UIActivityViewController has
init(activityItems: [Any], applicationActivities: [UIActivity]? = nil) {
self.activityItems = activityItems
self.applicationActivities = applicationActivities
super.init(nibName: nil, bundle: nil)
// Make transparent and covering entire screen
view.backgroundColor = .clear
modalPresentationStyle = .overCurrentContext
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Present UIActivityViewController here
presentShareSheet()
}
fileprivate func presentShareSheet() {
let shareSheet = UIActivityViewController(activityItems: activityItems,
applicationActivities: applicationActivities)
shareSheet.completionWithItemsHandler = { [weak self] _, _, _, _ in
// This is necessary to dismiss parent VC
self?.dismiss(animated: false)
}
self.present(shareSheet, animated: true)
}
}
And use it like UIActivityViewController but presenting it without animations
#objc private func shareImage() {
guard let image = imageView.image else { return }
let shareVC = ShareViewController(activityItems: [image])
present(shareVC, animated: false)
}

Show alert after dismissing presentingviewController

When a user purchased completion handler notify me and dismiss viewController. However, I want to display/show an alert to the user after viewController dismissed. At the moment when I step through in the debugger, it goes through the code but the alert isn't being shown. Still getting inbuilt in apple one that says All set. Is there a way I can display my alert after dismissing the viewController.
override func viewWillDisappear(_ pAnimated: Bool) {
super.viewWillDisappear(pAnimated)
self.notifyForUserHasPurchasedProduct {
self.presentingViewController?.dismiss(animated: true, completion: {
UIAlertController.bs_showAlertFrom(self, title: "AppName", message: "Thank you. Your purchase was successful")
})
}
}
You need to call self.present(alert, animated: true) to show alert. When ViewController self is not present, you need to change code to presentedViewController.present(alert, animated: true)
I have builded some functions:
extension UIViewController {
func topMostViewController() -> UIViewController {
if let presented = self.presentedViewController {
return presented.topMostViewController()
}
if let navigation = self as? UINavigationController {
return navigation.visibleViewController?.topMostViewController() ?? navigation
}
if let tab = self as? UITabBarController {
return tab.selectedViewController?.topMostViewController() ?? tab
}
return self
}
}
func getRootController () -> UIViewController { // function in global scope
return (UIApplication.shared.delegate?.window!!.rootViewController)!
}
And then use them like here:
override func viewWillDisappear(_ pAnimated: Bool) {
super.viewWillDisappear(pAnimated)
self.notifyForUserHasPurchasedProduct {
self.presentingViewController?.dismiss(animated: true, completion: {
let alert = UIAlertController(title: "AppName", message: "Thank you. Your purchase was successful", preferredStyle: .alert)
let topC = getRootController().topMostViewController()
topC.present(alert, animated: true, completion: nil)
})
}
}

Signup not proceeding to Tab View Controller

Once a user signs in to my app, I need to take them to a tab view controller so they can use the app to its fullest potential. I have tried to initiate the TabBarController in the buttons onClick function with no success.
PFUser.logInWithUsernameInBackground(username, password:password) {
(user: PFUser?, error: NSError?) -> Void in
if error == nil {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("KlikurHomeTabs") as! UITabBarController
self.presentViewController(vc, animated: true, completion: nil) // this shows it modally
} else if error!.code == 101 {
var invalidLogin:UIAlertView = UIAlertView(title: "Please try again", message: "The username password combo you have us does not match our records, please try again or reset your password.", delegate: self, cancelButtonTitle: "Try again")
invalidLogin.show()
}
}
Can anybody spot what I am doing wrong? I have no clue and have been trying for a while now. Thanks :)
Just change this line and also take out the storyboard line of code
let vc = storyboard.instantiateViewControllerWithIdentifier("KlikurHomeTabs") as! UITabBarController
To
let vc = self.storyboard.instantiateViewControllerWithIdentifier("KlikurHomeTabs")
self.presentViewController(vc!, animated: true, completion: nil)
This is more of an elaboration on Paulw11's comment, but here is what I am doing. I have a "splash" view controller that has 2 storyboard segues, one to a signin/signup view controller, and one to my main tabview controller. Inside viewDidAppear, I check the login status and then perform one of the two segues. Here is an example of the code.
override func viewDidAppear(animated: Bool) {
if needsLogin {
performSegueWithIdentifier("SignIn/SignUP", sender: self)
} else {
performSegueWithIdentifier("MainTabBar", sender: self)
}
}

Parse sign out function

I'm attempting a simple sign out function where the view returns to my login/sign up view after the user signs out. I have tried using these two methods, but the application crashes every time.
First Method:
#IBAction func signPressed(sender: AnyObject) {
PFUser.logOut()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("ViewController") as! UIViewController
presentViewController(vc, animated: true, completion: nil)
}
Second Method:
I created the following function:
func loginSetup() {
if (PFUser.currentUser() == nil) {
let vc = ViewController()
self.presentViewController(vc, animated: true, completion: nil)
}
}
then added it to my sign out function:
#IBAction func signPressed(sender: AnyObject) {
PFUser.logOut()
self.loginSetup()
}
both crashed and gave me an app delegate error.. whats the issue here?
here is screenshot of error given :
https://40.media.tumblr.com/1f044ecbdd5059836b0a360d16af9846/tumblr_nqzsobll0o1tupbydo1_1280.png
Providing you've set the root VC to the Login/Sign Up screen.
func didTapSignOut(sender: AnyObject)
{
PFUser.logOut()
self.navigationController?.popToRootViewControllerAnimated(true)
}
Then you can call this function in a UIButton IBAction but I call it on my UINavigationBar like so,
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Sign Out", style: .Plain, target: self, action: "didTapSignOut:")

Resources