perform segue after admob ad is dismissed - ios

any idea on how to perform this segue. Once users sign up and they are authenticated they will be shown an interstitial ad. however once the ad is done or dismissed. the segue to the next view controller should be performed. I not exactly sure what im missing in my code:
#IBAction func signUpBtn_TouchUpInside(_ sender: Any) {
view.endEditing(true)
ProgressHUD.show("Waiting...", interaction: false)
if let profileImg = self.selectedImage, let imageData = UIImageJPEGRepresentation(profileImg, 0.1) {
AuthService.signUp(username: usernameTextField.text!, email: emailTextField.text!, password: passwordTextField.text!, imageData: imageData, onSuccess: {
ProgressHUD.showSuccess("Success")
if self.interstitial.isReady {
self.interstitial.present(fromRootViewController: self)
} else {
print("Ad wasn't ready")
self.performSegue(withIdentifier: "signUpToTabbarVC", sender: nil)
}
self.performSegue(withIdentifier: "signUpToTabbarVC", sender: nil)
}, onError: { (errorString) in
ProgressHUD.showError(errorString!)
})
} else {
ProgressHUD.showError("Profile Image can't be empty")
}
}
and help or feedback is always greatly appreciated

You should conform your ViewController to interstitial delegate and perform the segue when interstitial is dismissed
extension ViewController: GADInterstitialDelegate {
func interstitialDidDismissScreen(_ ad: GADInterstitial) {
self.performSegue(withIdentifier: "signUpToTabbarVC", sender: nil)
}
}
And update signUpBtn_TouchUpInside method as below,
#IBAction func signUpBtn_TouchUpInside(_ sender: Any) {
view.endEditing(true)
ProgressHUD.show("Waiting...", interaction: false)
if let profileImg = self.selectedImage, let imageData = UIImageJPEGRepresentation(profileImg, 0.1) {
AuthService.signUp(username: usernameTextField.text!, email: emailTextField.text!, password: passwordTextField.text!, imageData: imageData, onSuccess: {
self.handleSignupSuccess()
}, onError: { (errorString) in
ProgressHUD.showError(errorString!)
})
} else {
ProgressHUD.showError("Profile Image can't be empty")
}
}
private func handleSignupSuccess() {
ProgressHUD.showSuccess("Success")
if self.interstitial.isReady {
self.interstitial.delegate = self
self.interstitial.present(fromRootViewController: self)
} else {
print("Ad wasn't ready"
self.performSegue(withIdentifier: "signUpToTabbarVC", sender: nil)
}
}

Related

Only instance methods can be declared #IBAction error?

I am facing this error on build for the function shown in the code
Only instance methods can be declared #IBAction
this error is coming up only after I introduced google sign in method for similar functionality , earlier it not an error
#IBAction func SignInButtonAction(_ sender: Any) {
guard let email = emailField.text else { return }
guard let pass = passwordField.text else { return }
Auth.auth().signIn(withEmail: email, password: pass) { user, error in
if error == nil && user != nil {
let setupcheckref = Firestore.firestore().collection("users").document(Auth.auth().currentUser!.uid)
setupcheckref.getDocument{(document, error) in
if let document = document, document.exists{
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
self.checksetup = document.get("setupComplete") as! Bool
if self.checksetup == true {
if Auth.auth().currentUser!.isEmailVerified {
self.performSegue(withIdentifier: "toLoginFeed", sender: self)
}
else{
print("please verify your email")
try! Auth.auth().signOut()
}
}
else{
self.view.makeToast("Please Setup Your Account!", duration: 2.5)
self.performSegue(withIdentifier: "fromlogintosetup", sender: self)
SVProgressHUD.dismiss()
} }
}
// self.dismiss(animated: false, completion: nil)
} else {
print("Error logging in: \(error!.localizedDescription)")
// self.resetForm()
// SVProgressHUD.dismiss()
}
}
}
That means you can create #IBActions only as instance methods of a class.
You might be creating it of a class.
class VC: UIViewController {
#IBAction func SignInButtonAction(_ sender: Any) {
//your code...
}
}

Passing data between controller after method is done executed [SWIFT]

I'm trying to send data across another view controller once a button is pressed (I know this question looks repetitive), however, the button being pressed is processing some data. So when the button is clicked, the other view controller is popped up before the needed actual data is sent. I tried both segue calls (prepare for segue and the calling segue) but none seem to work. Here is my code:
#IBAction func login(sender: Any) {
SparkCloud.sharedInstance().login(withUser: email, password: password) { (error:Error?) -> Void in
if let _ = error {
print("Wrong credentials or no internet connectivity, please try again")
}
else {
print("Logged in")
var myPhoton : SparkDevice?
SparkCloud.sharedInstance().getDevices { (devices:[SparkDevice]?, error:Error?) -> Void in
if let _ = error {
print("Check your internet connectivity")
}
else {
if let d = devices {
for device in d {
myPhoton = device
print(myPhoton!)
}
}
}
}
}
}
}
And the segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "loggedIn" {
if let destinationVC = segue.destination as? testViewController {
destinationVC.myPhoton = sentDevice
}
}
}
And the other view controller that is receiving the data:
var myPhoton : SparkDevice?
override func viewDidLoad() {
super.viewDidLoad()
print(myPhoton)
}
I receive 'nil', which indicates that when the data has been set, it was before it got set to the data that I wanted from the server. Can someone help me please?
You can try
#IBAction func login(sender: Any) {
SparkCloud.sharedInstance().login(withUser: email, password: password) { (error:Error?) -> Void in
if let _ = error {
print("Wrong credentials or no internet connectivity, please try again")
}
else {
print("Logged in")
var myPhoton : SparkDevice?
SparkCloud.sharedInstance().getDevices { (devices:[SparkDevice]?, error:Error?) -> Void in
if let _ = error {
print("Check your internet connectivity")
}
else {
if let d = devices {
for device in d {
myPhoton = device
print(myPhoton!)
}
self.performSegue(withIdentifier: "loggedIn", sender: myPhoton)
}
}
}
}
}
}
and remove linking the segue directly to the button action in IB
Edit
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "loggedIn" {
if let destinationVC = segue.destination as? testViewController {
destinationVC.myPhoton = sender as! SparkDevice
}
}
}
Instead of using Segue, you can also try doing it with code, i.e.
#IBAction func login(_ sender: UIButton)
{
SparkCloud.sharedInstance().login(withUser: email, password: password) {
if let _ = error
{
print("Wrong credentials or no internet connectivity, please try again")
}
else
{
print("Logged in")
var myPhoton : SparkDevice?
SparkCloud.sharedInstance().getDevices { (devices:[SparkDevice]?, error:Error?) -> Void in
if let _ = error
{
print("Check your internet connectivity")
}
else
{
if let d = devices
{
for device in d
{
myPhoton = device
print(myPhoton!)
//HERE..!!!!!
DispatchQueue.main.async {[weak self] in
let anotherController = self.storyboard?.instantiateViewController(withIdentifier: "AnotherVC") as! AnotherVC
anotherController.myPhoton = myPhoton
self.navigationController?.pushViewController(anotherController, animated: true)
}
}
}
}
}
}
}
}
In the above code, if you want to push the controller, then use:
self.navigationController?.pushViewController(anotherController, animated: true)
otherwise, if you want to present the controller, then use:
self.present(anotherController, animated: true, completion: nil)
Let me know if you still face any issues.

The method return the varible without modifying it

i have a problem with my code in Swift
the method verifyInput should return false when there's an error
but it always return true no matter what + when there's an error it print "error" but its just return true
please help
#IBAction func register(_ sender: UIButton) {
let check = verifyInput(email :email.text! ,password: password.text!)
if(check==true){
self.performSegue(withIdentifier: "goToAmazon", sender: nil)
} else if(check==false) {
self.message.text = "Sorry! there's an error"
}
}
func verifyInput(email: String, password: String) -> Bool {
var check = true
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
if error != nil {
print("error")
check = false
} else if(error==nil){
check = true
print("registered!")
}
}
return check
}
The problem is that verifyInput is being called synchronously from register but within it is an asynchronous call to Auth.auth().createUser with a completion block.
The check result is being returned before the asynchronous call ever completes. You need to change your method to be asynchronous as well.
Something vaguely like this is what you want:
#IBAction func register(_ sender: UIButton) {
if let email = email.text, let password = password.text {
verifyInput(email: email, password: password) { (check) in
DispatchQueue.main.async {
// only run UI code on the main thread
if(check){
self.performSegue(withIdentifier: "goToAmazon", sender: nil)
} else {
self.message.text = "Sorry! there's an error"
}
}
}
}
}
func verifyInput(email: String, password: String, escaping completion:#escaping (Bool)->Void) {
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
if error != nil {
print("error")
completion(false)
} else if(error==nil){
print("registered!")
completion(true)
}
}
}

Cannot get Plaid sandbox to work on iOS with Swift 3

When I use the un:user_good and pw:pass_good I get the attached screen
And it does not return a accessToken
I have already added my public key in my AppDelegate
[![#IBAction fu][1]][1]nc plaidConnectButton(_ sender: Any) {
let plaidLink = PLDLinkNavigationViewController(environment: .tartan, product: .connect)!
plaidLink.linkDelegate = self
plaidLink.providesPresentationContextTransitionStyle = true
plaidLink.definesPresentationContext = true
plaidLink.modalPresentationStyle = .custom
self.present(plaidLink, animated: true, completion: nil)
}
func linkNavigationContoller(_ navigationController: PLDLinkNavigationViewController!, didFinishWithAccessToken accessToken: String!) {
print("success \(accessToken)")
myAPIClient.connectAddBank(bankToken: accessToken, completion:{
(error) in
if(error != nil) {
print(error.debugDescription)
} else {
print("successfully added bank")
self.dismiss(animated: true, completion: nil)
}
})
}
func linkNavigationControllerDidFinish(withBankNotListed navigationController: PLDLinkNavigationViewController!) {
print("Manually enter bank info?")
self.performSegue(withIdentifier: "unlistedBankSegue", sender: self)
}
func linkNavigationControllerDidCancel(_ navigationController: PLDLinkNavigationViewController!) {
self.dismiss(animated: true, completion: nil)
}
Please help
Set your environment to .sandbox during the init process.
Plaid support link for this: https://github.com/plaid/link/issues/140

ViewController loads but does not show

I'm using the Spotify iOS SDK. When a user logs into Spotify using the app, on call back loginVC transitions to musicPlayerVC. But, when a user logs into the app using a web view, once the web view dismisses and the loginVC is shown, the musicPlayerVC is loaded (print statements from viewDidLoad occur), but loginVC does not dismiss and musicPlayerVC does not show.
loginVC:
class loginVC: UIViewController, SPTStoreControllerDelegate, WebViewControllerDelegate {
#IBOutlet weak var statusLabel: UILabel!
var authViewController: UIViewController?
var firstLoad: Bool!
var Information: [String:String]?
override func viewDidLoad() {
super.viewDidLoad()
// NotificationCenter.default.addObserver(self, selector: #selector(self.sessionUpdatedNotification), name: NSNotification.Name(rawValue: "sessionUpdated"), object: nil)
self.statusLabel.text = ""
self.firstLoad = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(self.sessionUpdatedNotification), name: NSNotification.Name(rawValue: "sessionUpdated"), object: nil)
let auth = SPTAuth.defaultInstance()
// Uncomment to turn off native/SSO/flip-flop login flow
//auth.allowNativeLogin = NO;
// Check if we have a token at all
if auth!.session == nil {
self.statusLabel.text = ""
return
}
// Check if it's still valid
if auth!.session.isValid() && self.firstLoad {
// It's still valid, show the player.
print("View did load, still valid, showing player")
self.showPlayer()
return
}
// Oh noes, the token has expired, if we have a token refresh service set up, we'll call tat one.
self.statusLabel.text = "Token expired."
if auth!.hasTokenRefreshService {
self.renewTokenAndShowPlayer()
return
}
// Else, just show login dialog
}
override var prefersStatusBarHidden: Bool {
return true
}
func getAuthViewController(withURL url: URL) -> UIViewController {
let webView = WebViewController(url: url)
webView.delegate = self
return UINavigationController(rootViewController: webView)
}
func sessionUpdatedNotification(_ notification: Notification) {
self.statusLabel.text = ""
let auth = SPTAuth.defaultInstance()
self.presentedViewController?.dismiss(animated: true, completion: { _ in })
if auth!.session != nil && auth!.session.isValid() {
self.statusLabel.text = ""
print("Session updated, showing player")
self.showPlayer()
}
else {
self.statusLabel.text = "Login failed."
print("*** Failed to log in")
}
}
func showPlayer() {
self.firstLoad = false
self.statusLabel.text = "Logged in."
self.Information?["SpotifyUsername"] = SPTAuth.defaultInstance().session.canonicalUsername
OperationQueue.main.addOperation {
[weak self] in
self?.performSegue(withIdentifier: "ShowPlayer", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowPlayer" {
if let destination = segue.destination as? PlayController {
destination.Information = self.Information
}
}
}
internal func productViewControllerDidFinish(_ viewController: SPTStoreViewController) {
self.statusLabel.text = "App Store Dismissed."
viewController.dismiss(animated: true, completion: { _ in })
}
func openLoginPage() {
self.statusLabel.text = "Logging in..."
let auth = SPTAuth.defaultInstance()
if SPTAuth.supportsApplicationAuthentication() {
self.open(url: auth!.spotifyAppAuthenticationURL())
} else {
self.authViewController = self.getAuthViewController(withURL: SPTAuth.defaultInstance().spotifyWebAuthenticationURL())
self.definesPresentationContext = true
self.present(self.authViewController!, animated: true, completion: { _ in })
}
}
func open(url: URL) {
if #available(iOS 10, *) {
UIApplication.shared.open(url, options: [:],
completionHandler: {
(success) in
print("Open \(url): \(success)")
})
} else {
let success = UIApplication.shared.openURL(url)
print("Open \(url): \(success)")
}
}
func renewTokenAndShowPlayer() {
self.statusLabel.text = "Refreshing token..."
SPTAuth.defaultInstance().renewSession(SPTAuth.defaultInstance().session) { error, session in
SPTAuth.defaultInstance().session = session
if error != nil {
self.statusLabel.text = "Refreshing token failed."
print("*** Error renewing session: \(error)")
return
}
self.showPlayer()
}
}
func webViewControllerDidFinish(_ controller: WebViewController) {
// User tapped the close button. Treat as auth error
}
}
webController :
import UIKit
import WebKit
#objc protocol WebViewControllerDelegate {
func webViewControllerDidFinish(_ controller: WebViewController)
/*! #abstract Invoked when the initial URL load is complete.
#param success YES if loading completed successfully, NO if loading failed.
#discussion This method is invoked when SFSafariViewController completes the loading of the URL that you pass
to its initializer. It is not invoked for any subsequent page loads in the same SFSafariViewController instance.
*/
#objc optional func webViewController(_ controller: WebViewController, didCompleteInitialLoad didLoadSuccessfully: Bool)
}
class WebViewController: UIViewController, UIWebViewDelegate {
var loadComplete: Bool = false
var initialURL: URL!
var webView: UIWebView!
var delegate: WebViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
print(initialURL)
let initialRequest = URLRequest(url: self.initialURL)
self.webView = UIWebView(frame: self.view.bounds)
self.webView.delegate = self
self.webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.view.addSubview(self.webView)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.done))
self.webView.loadRequest(initialRequest)
}
func done() {
self.delegate?.webViewControllerDidFinish(self)
self.presentingViewController?.dismiss(animated: true, completion: { _ in })
}
func webViewDidFinishLoad(_ webView: UIWebView) {
if !self.loadComplete {
delegate?.webViewController?(self, didCompleteInitialLoad: true)
self.loadComplete = true
}
}
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
if !self.loadComplete {
delegate?.webViewController?(self, didCompleteInitialLoad: true)
self.loadComplete = true
}
}
init(url URL: URL) {
super.init(nibName: nil, bundle: nil)
self.initialURL = URL as URL!
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}

Resources