Admob display interstitial before segue - Swift - ios

I have a button that segue's over to another view. When the user clicks this button, I want to display an interstitial ad (if one is loaded) and then once the user dismisses the interstitial ad, then perform the segue as usual. If there was no interstitial ad, then perform the segue as normal.
I have some code that will display an interstitial, but when the user dismisses it, it takes them back to the previous view controller. They have to click the button again to be taken to the next view controller. Any tips?
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(interstitial.isReady) {
interstitial.presentFromRootViewController(self)
}
}

I wanted to do the same thing. Once they watch the ad, I want it to proceed with the regular segue. So I added an alert with a callback. The only difference was mine was a UITableViewCell tap. In your case just do something like this:
#IBAction func buttonTapped(sender: UIButton)
{
self.presentViewController(interstitialAdAlert(
{ adWatched in
if adWatched
{
// perform segue here
}
}),
animated: true,
completion: nil)
}
Where adWatched is the callback parameter and interstitialAdAlert(watchAdCallback: (adWatched: Bool) is function that presents the alert as seen below:
func interstitialAdAlert(watchAdCallback: (adWatched: Bool) -> ()) -> UIAlertController
{
let alert = UIAlertController(title: "Watch Ad?", message: "Your message here.", preferredStyle: .Alert)
let watchAdAction = UIAlertAction(title: "Watch Ad", style: .Default)
{ (_) in
self.interstitial.isReady ? self.interstitial.presentFromRootViewController(self) : DDLogSwift.debug("The interstitial ad couldn't be loaded.")
watchAdCallback(adWatched: true)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel)
{ (_) in
watchAdCallback(adChosen: false)
}
alert.addAction(watchAdAction)
alert.addAction(cancelAction)
return alert
}
Hope this helps. Works like a charm for me with my tableview!
Oh, also make sure you create and load the interstitial ad in viewWillAppear.

Related

How to present action sheet form a View Controller that present modally?

I have a ViewControllerA that already show as pop out,which is present modally. Inside this ViewControllerA have a tableview with tableViewCell .So in each cell have a button.When users click on this button,I want to show actionSheet at the bottom of the screen.
Here is my code:
TableViewCell class,here I connect the button to the IBAction
protocol MyDelegate: class {
func showDropDownMenu()
}
class tableCell: UITableViewCell {
weak var delegate: MyDelegate?
#IBAction func dropDownButton(_ sender: Any) {
print("print something")
self.delegate?.showDropDownMenu()
}
}
ViewControllerA
class ViewControllerA: UIViewController , UITableViewDataSource, UITableViewDelegate,MyDelegate {
func showDropDownMenu() {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
// Create your actions - take a look at different style attributes
let hideAction = UIAlertAction(title: "Hide", style: .default) { (action) in
print("didPress hide")
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
print("didPress cancel")
}
actionSheet.addAction(hideAction)
actionSheet.addAction(cancelAction)
self.present(actionSheet, animated: true, completion: nil)
}
Suppose when click on the button will call the function showDropDownMenu() in ViewControllerA.Now I click on dropDownButton it will show print something in console(means no problem with the button),but the actionSheet not show up on the bottom.
I not sure what is the problem here,but I suspect is cause by ViewControllerA is present using segue with properties like so:
Kind: Present modally ,Presentation: Over Current Context ,Transition:
Cover Vertical
If this is the reason,please help me how to present an actionsheet from a View Controller that presented modally. Thank you
Code for showing ViewControllerA :
func showViewControllerA(Id: Int) {
self.performSegue(withIdentifier: "showViewControllerA", sender: Id)
}
Refer this link. Though it's for IPad, it will give you a brief idea of where and how to present the action sheet
https://medium.com/#nickmeehan/actionsheet-popover-on-ipad-in-swift-5768dfa82094
I have faced a similar scenario of what you are trying to achive, and this solution which i provided above helped me out. Hope, it helps you out as Well.
Make sure you have set value for delegate. For example
cell.delegate = self;

How to continue with segue after checking fields with shouldPerformSegue() in Swift

with the shouldPerforSegue() func I am able to check some fields before seguing, however, I need it to continue with the segue even if the fields were bad at the time of triggering the segue.
Right now, when the user clicks on a button that triggers a segue, I am checking to see if the images are already uploaded to the server. I display a progress bar along with an alert to indicate the % left. However, right now after the image is uploaded to the server with the progress bar indicating 100%. I still have to manually click "ok" and re-click the seguing button. I am trying to see if there was a way to bypass this hindrance, by just continuing with the segue.
I have tried programmatically triggering the segue button after the image is uploaded, but it does not work as intended.
UIApplication.shared.sendAction(self.saveButton.action!, to: self.saveButton.target, from: nil, for: nil)
The function I have that checks for validation:
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if ((sender as? UIBarButtonItem) != nil) && uploadingImagesToFirebase {
// Create the alert controller
let alertController = UIAlertController(title: "Uploading Images...", message: "", preferredStyle: .alert)
// Create an ok button
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default) { (result : UIAlertAction) -> Void in
print("OK")
}
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: {
// Add your progressbar after alert is shown (and measured)
let rect = CGRect(x: alertController.view.frame.width * 0.10, y: alertController.view.frame.height / 2, width: alertController.view.frame.width * 0.80, height: 100)
self.progressView = UIProgressView(frame: rect)
alertController.view.addSubview(self.progressView!)
})
return false
}
return true
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// If user clicks on a job cell
if segue.identifier == "showJobDetails" {
...
}
else if addJobButton == sender as? UIButton {
print("Adding a new job from customer view")
...
}
// If save button was choice selected by user
else if segue.identifier == "identifier {
customer.firstName = firstNameTextField.text
customer.middleName = middleNameTextField.text
customer.lastName = lastNameTextField.text
customer.address = addressTextField.text
customer.email = emailTextField.text
customer.phone = phoneTextField.text
customer.jobs = customerJobs
updateCustomerValuesInFirebase()
updateJobValuesInFirebase()
}
}
Before checking (by using the shouldPerformSegue(withIdentifier:sender:)), you should perform it first, you can achieve this by using performSegueWithIdentifier:sender::
Initiates the segue with the specified identifier from the current
view controller's storyboard file.
Actually, shouldPerformSegue(withIdentifier:sender:) methods does the following:
Determines whether the segue with the specified identifier should be
performed.
So you should do:
performSegue(withIdentifier: "identifier", sender: self)
before checking by using shouldPerformSegue(withIdentifier:sender:).
If you don't know how to set the identifier for the segue, check this answer.
in Swift3, you have to perform the segue by this line of code:
performSegue(withIdentifier: identifier, sender: sender)
the identifier and sender values are depends on where you call the performSegue, for example if you are in shouldPerformSegue function you can use the function input values, but if you are in other functions you have to add the identifier by yourself(which you set it for the segue in storyboard) and set the sender to nil.

Showing alert after unwind segue stops the segue. How do I make sure alert is shown after unwind segue is completed?

I have an unwind segue from A view controller to B view controller.
A network operation is done in B. After the operation is completed, the response will be shown in A view controller.
I successfully made this structure. However there is an issue:
When I try to show the alert, it shows but stops the segue. How do i make sure alert shows after segue is completed.
The error is here:
2016-04-27 14:39:28.350 PROJECT[9100:128844] Presenting view controllers on detached view controllers is discouraged <PROJECT.FeedTableViewController: 0x7a928c00>.
2016-04-27 14:39:28.359 PROJECT[9100:128844] popToViewController:transition: called on <UINavigationController 0x7c12a800> while an existing transition or presentation is occurring; the navigation stack will not be updated.
Unwind handler in A:
#IBAction func unwindToFeed(segue: UIStoryboardSegue) {
jsonArray[rowFromShare!]["ApplicationDataUsers"] = jsonFromShare!
tableView.reloadData()
ShowErrorDialog("Success", message: successMessageFromShare!, buttonTitle: "OK")
}
//Error Dialog
func ShowErrorDialog(title:String, message:String, buttonTitle:String){
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
}
Unwind trigger in B:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "unwindToFeed"{
let feedTable = segue.destinationViewController as! FeedTableViewController
feedTable.rowFromShare = row
feedTable.jsonFromShare = jsonToShare
feedTable.successMessageFromShare = successMessageToShare
}
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
A = FeedTableViewController
B = ShareTableViewController
How do I make sure alert is shown after segue is done?
The unwindToFeed method is called before the unwind segue is complete, as you have found.
One approach would be to set a boolean in the unwindToFeed method and then check this boolean in viewDidAppear, when you know the segue is complete. If the boolean is set then you can display the alert:
#IBAction func unwindToFeed(segue: UIStoryboardSegue) {
jsonArray[rowFromShare!]["ApplicationDataUsers"] = jsonFromShare!
tableView.reloadData()
self.unwinding = true
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if (self.unwinding) {
self.ShowErrorDialog("Success", message: successMessageFromShare!, buttonTitle: "OK")
self.unwinding=false
}

iOS Xcode (swift) - how to execute code after unwind segue

I perform a segue from scene 1 to scene 2. I then return from scene 2 to scene 1. How do I not only pass data from scene 2 to scene 1 but detect in scene 1 that I've returned from scene 2 and execute code in scene 1?
In Android I do this with startActivity and onActivityResult.
Introducing Bool state like the other answer's suggesting is very bad and must be avoided if possible as it greatly increases the complexity of your app.
Amongst many other patterns, easiest one to solve this kind of problem is by passing delegate object to Controller2.
protocol Controller2Delegate {
func controller2DidReturn()
}
class Controller1: Controller2Delegate {
func controller2DidReturn() {
// your code.
}
func prepareForSegue(...) {
// get controller2 instance
controller2.delegate = self
}
}
class Controller2 {
var delegate: Controller2Delegate!
func done() {
// dismiss viewcontroller
delegate.controller2DidReturn()
}
}
States are evil and is the single biggest source of software bugs.
you could do it like this:
class SourceViewController: UIViewController {
var didReturnFromDestinationViewController = false
#IBAction func returnToSourceViewController(segue: UIStoryboardSegue) {
didReturnFromDestinationViewController = true
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if didReturnFromDestinationViewController == true {
// reset the value
didReturnFromDestinationViewController = false
// do whatever you want
}
}
}
The problem I was having was that I was trying to show an alert dialog after the unwind segue had finished. So my View Controller 2 performed an unwind segue to View Controller 1. What I found is that the code that runs after the unwind segue method is called runs before View Controller 2 is dismissed, so when I tried to show an alert dialog, it would disappear as soon as View Controller 2 was dismissed.
If the other solutions don't work for you, do what I did. I added a viewWillAppear override to my class and dismissed the parent controller there, then added the code for my alert dialog after that. To make sure viewWillAppear wasn't showing the alert dialog the first time View Controller 1 was presented, I set up an if statement checking for the name of a variable that I declared in the class and had set equal to "". Then in View Controller 2 I passed some text in the variable back to View Controller 1, so when the if statement runs it tests the variable not equal to "", and when it finds it's not, the code is run. In my case the variable was named "firstname".
override func viewWillAppear(_ animated: Bool) {
if firstname != "" {
self.parent?.dismiss(animated: true, completion: nil)
//CustomViewController?.dismiss(animated: true, completion: nil)
let alertController = UIAlertController(title: "Hello", message: "This is a test", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Close Alert", style: .default, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
}
}

How to create modal list in Swift/iOS

I'm trying to recreate a modal list popover in Swift, similar to the ones found in other several popular applications. See below for examples.
My current attempt looks like this:
#IBAction func showListOptions(sender: AnyObject) {
// segue set to "Present Modally"
// Presentation set to "Over Current Context"
self.performSegueWithIdentifier("ShowListItems", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var vc = segue.destinationViewController as! UIViewController
vc.view.backgroundColor = UIColor(red:0, green:0, blue:0, alpha:0.3)
}
The next view is a regular ViewController with a few buttons with their layout relative to the bottom of the screen.
A few things to note, when I set the Presentation style of the segue to "Full Screen", the background turns full black (instead of the desired alpha (rgba(0, 0, 0, 0.3)).
Setting the Presentation to "Over Current Context", I at least get the alpha color background, but I'm still able to click around on my tabbar at the bottom... which then turns my modal back to a black screen.
Help is much appreciated! Thank you.
In the second example is an UIActionSheet (easier to implement).
The first one is an UIView with low alpha (about a BlackColor with 0.5 alpha) with an UITableView constrained to bottom, trailing and leading. That with a keyframe animation. Using a UIViewController isn't the easiest approx. on this situation.
If you are targeting iOS 7.0 and up then you can do UIActionSheet
let myActionSheet = UIActionSheet()
myActionSheet.delegate = self
myActionSheet.addButtonWithTitle("Add event")
myActionSheet.addButtonWithTitle("close")
myActionSheet.cancelButtonIndex = 1
myActionSheet.showInView(self.view)
func actionSheet(myActionSheet: UIActionSheet!, clickedButtonAtIndex buttonIndex: Int){
if(myActionSheet.tag == 1){
if (buttonIndex == 0){
println("Do something")
}
}
}
if you are targeting iOS 8.0 and up then do UIAlertController
let myAlertController = UIAlertController(title: nil, message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
let otherAction = UIAlertAction(title: "other", style: .Default, handler: otherHandler)
myAlertController.addAction(cancelAction)
myAlertController.addAction(otherAction)
self.presentViewController(myAlertController, animated: true, completion: nil)
func otherHandler(alertAction: UIAlertAction) {
//Do something when other button is tapped
}
Thanks to #pbush25 - what I am really looking for is a UIAlertController of type ActionSheet. This ultimately does all the work for you :)
The tutorial (written in Swift for iOS 8) can be found here http://ioscreator.com/tutorials/action-sheet-tutorial-ios8-swift

Resources