How to properly implement Stripe in iOS project? - ios

Im developing an iOS app and its includes selling goods outside of the app so I downloaded Stripe using Cocoapods and placing it in my poodle. I know I have correctly installed in my app and input my test API key, because it import Stripe line works just fine. However I am having trouble creating a token. Every time I try to run my code in the simulator and try to make a purchase it prints there was an error. I don't know if its because I implemented the wrong line of code somewhere or left some out, so I was wondering if anybody could help me figure out why the purchase isn't going through? I know I don't have a backend set up but I'm not trying to send the token to the server yet I'm just trying to make sure my app is connected to Stripe which is the first step of 6 that require to actually make a purchase. Thanks for your help in advance.
Code for view controller before the one that lets user (through firebase authentication) make a purchase and stores data:
import UIKit
class PaymentInfoController: UIViewController {
#IBOutlet weak var paymentLabel: UILabel!
#IBOutlet weak var cardField: UITextField!
#IBOutlet weak var cvcField: UITextField!
#IBOutlet weak var expField: UITextField!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let checkoutVC = segue.destination as? CheckoutController {
checkoutVC.cardNumber = self.cardField.text!
checkoutVC.cvc = self.cvcField.text!
if self.expField.text?.isEmpty == false {
expField.text?.contains("0123456789/")
(expField.text?.characters.count)! <= 7
let expDate = self.expField.text?.components(separatedBy: "/")
let expMonth = UInt((expDate?[0])!)
let expYear = UInt((expDate?[1])!)
checkoutVC.expMon = expMonth!
checkoutVC.expYear = expYear!
}
}
}
#IBAction func checkout(_ sender: Any) {
performSegue(withIdentifier: "checkout", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
Code for view controller where the purchase is made:
import UIKit
import FirebaseAuth
import FirebaseDatabase
import Firebase
import Stripe
class CheckoutController: UIViewController {
let ref = Database.database().reference()
#IBOutlet weak var feeLabel: UILabel!
#IBOutlet weak var amountLabel: UILabel!
var cardNumber = String()
var cvc = String()
var expMon = UInt()
var expYear = UInt()
#IBAction func purchase(_ sender: Any) {
if Auth.auth().currentUser != nil {
// Initiate the card
let stripCard = STPCard()
STPAPIClient.shared().createToken(withCard: stripCard, completion: { (token, error) -> Void in
if error != nil {
print("There is an error")
}
else {
// Send the card info to Strip to get the token
stripCard.number = self.cardNumber
stripCard.cvc = self.cvc
stripCard.expMonth = UInt(self.expMon)
stripCard.expYear = UInt(self.expYear)
let alert = UIAlertController(title: "Your Stripe token is " + (token?.tokenId)!, message: "", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(defaultAction)
self.present(alert, animated: true, completion: nil)
print(token!)
}
})
}
}
override func viewDidLoad() {
super.viewDidLoad()
let user = Auth.auth().currentUser
let userID: String = (user?.uid)!
if user != nil {
let totalRef = ref.child("users/\(userID)").child("Total")
totalRef.observeSingleEvent(of: .value, with: { (snapshot) in
let cost = snapshot.value as! Int
self.totalLabel.text = "\(cost) bookies"
let total = (Double(cost) * 1.35) + 1.39
self.amountLabel.text = "$\(total)"
})
}
}

The problem is that you're submitting a blank STPCard. You are calling the createToken method without setting any of the fields on the card. For some reason, it looks like you're only setting the card fields in the Completion block after you've gotten a token. You need to move these lines:
stripCard.number = self.cardNumber
stripCard.cvc = self.cvc
stripCard.expMonth = UInt(self.expMon)
stripCard.expYear = UInt(self.expYear)
up before you make the call to createToken.

Related

How to pass data from view controller to other view controller [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 2 years ago.
iā€™m newbie in swift language and i want to pass the price from the Item view controller to other controller (Payment view controller) using array. Can anyone help me? Thank you
Here the code for the item detail view controller
import UIKit
class ItemDetailViewController: UIViewController {
var items = [item]()
var name : String = ""
var price : String = ""
var imagee : String = ""
#IBOutlet weak var labelname: UILabel!
#IBOutlet weak var image: UIImageView!
#IBOutlet weak var labelprice: UILabel!
// This one got error.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
var DestViewController : PaymentViewController = segue.destination as! PaymentViewController
DestViewController.price = labelprice?[IndexPath.text]
}
#IBAction func addtoPayment(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
labelname.text = name
labelprice.text = price
image.image = UIImage(named: imagee)
}
}
And here the code for the payment
import UIKit
class PaymentViewController: UIViewController {
var items = [item]()
var price : String = ""
#IBOutlet weak var paymentdetails: UILabel!
#IBOutlet weak var cardnametextfield: UITextField!
#IBOutlet weak var validthrutextfield: UITextField!
#IBOutlet weak var cardnumbertextfield: UITextField!
#IBOutlet weak var cvcnumbertextfield: UITextField!
#IBOutlet weak var labelprice: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
labelprice.text = price
// Do any additional setup after loading the view.
}
#IBAction func paybutton(_ sender: Any) {
if cardnametextfield.text == "" {
alertMessage(titleInput: "Error, Payment Unsuccessful!", messageInput: "Please Fill all the fields")
} else if validthrutextfield.text == "" {
alertMessage(titleInput: "Error, Payment Unsuccessful!", messageInput: "Please Fill all the fields")
} else if cardnumbertextfield.text == "" {
alertMessage(titleInput: "Error, Payment Unsuccessful!", messageInput: "Please Fill all the fields")
} else if cardnumbertextfield.text == "" {
alertMessage(titleInput: "Error, Payment Unsuccessful!", messageInput: "Please Fill all the fields")
} else {
alertMessage(titleInput: "Success!", messageInput: "Payment Successful!")
self.transitionToHomePage()
}
}
func alertMessage(titleInput: String, messageInput: String){
let alert = UIAlertController(title: titleInput, message: messageInput, preferredStyle: UIAlertController.Style.alert)
let paybutton = UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil)
alert.addAction(paybutton)
self.present(alert, animated: true, completion: nil)
}
func transitionToHomePage(){
let TabHomeViewController = storyboard?.instantiateViewController(identifier: Constrants.Storyboard.TabHomeViewController) as? UITabBarController
view.window?.rootViewController = TabHomeViewController
view.window?.makeKeyAndVisible()
}
}
you can use this code ... try to use first letter small for objects
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
var destViewController : PaymentViewController = segue.destination as! PaymentViewController
if let lText = labelprice?.text {
destViewController.price = lText
}
}
If you want to unwrap:
DestViewController.price = labelprice?.text ?? ā€œā€
This way is not recommended but you can use
DestViewController.price = labelprice!.text
Search for unwarp in Swift

How to keep label results on secondViewController?

I am currently working on an app and I am stuck on the following: I have my mainVC (ReceiveInputVC), which after I enter an input, it goes to the secondVC (TimeLeftVC) and it updates all of its labels with results from the inputs received from the mainVC. My question is: How can I, after clicking on the arrow to go back to the mainVC or even if I close the app, when I click on the arrow from the mainVC to go to the secondVC have my labels showing the same values as before the user closed the application or returned to the main screen?
import UIKit
extension UIViewController {
func hideKeyboard() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
view.addGestureRecognizer(tap)
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
}
class ReceiveInputVC: UIViewController {
#IBOutlet weak var hourglassButton: UIButton!
#IBOutlet weak var whatIsYourAgeField: UITextField!
#IBOutlet weak var ageToDieField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.hideKeyboard()
}
#IBAction func arrowBtnPressed(_ sender: Any) {
// When pressed should show go to TimeLeftVC and show last result from the first time user entered the inputs, if nothing has been typed yet and no data has been saved an alert should pop up asking the user to enter an input on both fields
}
#IBAction func hourglassBtnPressed(_ sender: Any) {
let checkAgeField: Int? = Int(whatIsYourAgeField.text!)
let checkDyingAgeField: Int? = Int(ageToDieField.text!)
if (whatIsYourAgeField.text == "" || ageToDieField.text == "") || (whatIsYourAgeField.text == "" && ageToDieField.text == "") {
alert(message: "You must enter an input on both fields")
} else if checkAgeField! < 1 || checkDyingAgeField! > 100 {
alert(message: "You must enter an age higher than 1 and a dying age lower than 100")
} else if (checkAgeField! > checkDyingAgeField!) || (checkAgeField! == checkDyingAgeField!) {
alert(message: "You must enter an age lower than a dying age")
} else {
performSegue(withIdentifier: "goToSecondScreen", sender: self)
}
}
func alert(message: String, title: String = "Alert") {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Try Again", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
// Passing the data entered from ReceiveInputVC to TimeLeftVC
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToSecondScreen" {
let destinationTimeLeftVC = segue.destination as! TimeLeftVC
destinationTimeLeftVC.ageReceived = whatIsYourAgeField.text
destinationTimeLeftVC.ageToDieReceived = ageToDieField.text
}
}
}
import CircleProgressBar
class TimeLeftVC: UIViewController {
var ageReceived: String! // receive whatIsYourAgeField data from ReceiveInputVC
var ageToDieReceived: String! // receive ageToDieField data from ReceiveInputVC
#IBOutlet weak var yearsLeftLabel: UILabel!
#IBOutlet weak var daysLeftLabel: UILabel!
#IBOutlet weak var hoursLeftLabel: UILabel!
#IBOutlet weak var progressBar: CircleProgressBar!
override func viewDidLoad() {
super.viewDidLoad()
createResults()
}
func createResults() {
if let userAge = Int(ageReceived), let dyingAge = Int(ageToDieReceived) {
let yearsLeft = dyingAge - userAge
let daysLeft = yearsLeft * 365
let hoursLeft = daysLeft * 24
// Update UI
yearsLeftLabel.text = "\(yearsLeft)"
daysLeftLabel.text = "\(daysLeft)"
hoursLeftLabel.text = "\(hoursLeft)"
let percentage = (CGFloat(yearsLeft) / CGFloat(dyingAge)) * 100
let formatted = String(format: "%.1f", percentage)
// Update Circle Progress Bar
progressBar.setHintTextGenerationBlock { (progress) -> String? in
return String.init(format: "\(formatted)%%", arguments: [progress])
}
progressBar.setProgress(percentage/100, animated: true, duration: 4.0)
}
}
Project on GitHub: https://github.com/mvvieira95/Time-Life.git
You can use Coredata or another data base or user default
User default implementation:
#IBAction func arrowBtnPressed(_ sender: Any) {
UserDefaults.standard.set("your input values from text field or ...", forKey: "key")
}
In second view controller get it with
UserDefaults.standard.string(forKey: "key")
You can save and restore states with these methods
application:shouldSaveApplicationState and application:shouldRestoreApplicationStat.
Example:
func application(_ application: UIApplication,
shouldSaveApplicationState coder: NSCoder) -> Bool {
// Save the current app version to the archive.
coder.encode(11.0, forKey: "MyAppVersion")
// Always save state information.
return true
}
func application(_ application: UIApplication,
shouldRestoreApplicationState coder: NSCoder) -> Bool {
// Restore the state only if the app version matches.
let version = coder.decodeFloat(forKey: "MyAppVersion")
if version == 11.0 {
return true
}
// Do not restore from old data.
return false
}
You can explore the document in https://developer.apple.com/documentation/uikit/view_controllers/preserving_your_app_s_ui_across_launches?language=objc
Thanks guys, I came up with a solution:
class ReceiveInputVC: UIViewController {
#IBAction func arrowBtnPressed(_ sender: Any) {
let defaults = UserDefaults.standard
if let _ = defaults.object(forKey: "yearsSaved"), let _ = defaults.object(forKey: "daysSaved"), let _ = defaults.object(forKey: "hoursSaved") {
performSegue(withIdentifier: "goToSecondScreen", sender: self)
} else {
alert(message: "You must first enter an input")
}
}
class TimeLeftVC: UIViewController {
var ageReceived: String! // receive whatIsYourAgeField data from ReceiveInputVC
var ageToDieReceived: String! // receive ageToDieField data from ReceiveInputVC
#IBOutlet weak var yearsLeftLabel: UILabel!
#IBOutlet weak var daysLeftLabel: UILabel!
#IBOutlet weak var hoursLeftLabel: UILabel!
#IBOutlet weak var progressBar: CircleProgressBar!
override func viewDidLoad() {
super.viewDidLoad()
let defaults = UserDefaults.standard
yearsLeftLabel.text = defaults.object(forKey: "yearsSaved") as? String
daysLeftLabel.text = defaults.object(forKey: "daysSaved") as? String
hoursLeftLabel.text = defaults.object(forKey: "hoursSaved") as? String
}
override func viewWillAppear(_ animated: Bool) {
createResults()
}
func createResults() {
if let userAge = Int(ageReceived), let dyingAge = Int(ageToDieReceived) {
let yearsLeft = dyingAge - userAge
let daysLeft = yearsLeft * 365
let hoursLeft = daysLeft * 24
// Update UI
yearsLeftLabel.text = "\(yearsLeft)"
daysLeftLabel.text = "\(daysLeft)"
hoursLeftLabel.text = "\(hoursLeft)"
// Store Data
let defaults = UserDefaults.standard
defaults.set(yearsLeftLabel.text, forKey: "yearsSaved")
defaults.set(daysLeftLabel.text, forKey: "daysSaved")
defaults.set(hoursLeftLabel.text, forKey: "hoursSaved")
// Update Circle Progress Bar
let percentage = (CGFloat(yearsLeft) / CGFloat(dyingAge)) * 100
let formatted = String(format: "%.1f", percentage)
progressBar.setHintTextGenerationBlock { (progress) -> String? in
return String.init(format: "\(formatted)%%", arguments: [progress])
}
progressBar.setProgress(percentage/100, animated: true, duration: 4.0)
}
}
Having troubles now updating that progressBar when I go back to the view...

IOS - Limit user to choose at most 8 images and upload multiple images to Firebase using a For-loop

I am new to IOS. I am building an image sharing app with Xcode and Swift
I am stuck in images uploading part.
How can I limit users to choose 8 images at most and then upload the chosen pictures to Firebase using a For-loop?
I would like to use For-loop since I want to set the first picture as an icon picture.
Below is what I am able to do now
I created a SignUp page and allow a user to use ImagePicker to select 1 image and upload it to Firebase. Below is my code.
import UIKit
import Firebase
class SignUpViewController: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate
{
#IBOutlet weak var iconfield: UIImageView!
#IBOutlet weak var usernamefield: UITextField!
#IBOutlet weak var emailfield: UITextField!
#IBOutlet weak var passwordfield: UITextField!
#IBOutlet weak var confirmpasswordfield: UITextField!
#IBOutlet weak var signupbutton: UIButton!
let picker = UIImagePickerController()
var userStorage: StorageReference!
var ref: DatabaseReference!
override func viewDidLoad()
{
super.viewDidLoad()
picker.delegate = self
let storage = Storage.storage().reference(forURL: "gs://whatisit-8484a.appspot.com/")
ref = Database.database().reference()
userStorage = storage.child("users")
// Do any additional setup after loading the view.
iconfield.layer.cornerRadius=iconfield.frame.size.width/2
iconfield.clipsToBounds = true
}
#IBAction func selectionpressed(_ sender: Any)
{
picker.allowsEditing = true
picker.sourceType = .photoLibrary
present(picker,animated:true,completion:nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
if let image = info[UIImagePickerControllerEditedImage] as? UIImage
{
self.iconfield.image = image
signupbutton.isHidden = false
}
self.dismiss(animated:true,completion:nil)
}
#IBAction func confirmsignup(_ sender: Any)
{
guard usernamefield.text != "",emailfield.text != "",passwordfield.text != "", confirmpasswordfield.text != "" else {return}
if passwordfield.text == confirmpasswordfield.text
{
Auth.auth().createUser(withEmail: emailfield.text!, password: passwordfield.text!, completion: { (user, error) in
if let error = error
{
print(error.localizedDescription)
}
if let user = user
{
let changeRequest = Auth.auth().currentUser!.createProfileChangeRequest()
changeRequest.displayName = self.usernamefield.text!
changeRequest.commitChanges(completion: nil)
let imageRef = self.userStorage.child("\(user.uid).jpg")
let data = UIImageJPEGRepresentation(self.iconfield.image!, 0.5)
let uploadTask = imageRef.putData(data!, metadata: nil, completion: { (metadata, err) in
if err != nil{
print(err!.localizedDescription)
}
imageRef.downloadURL(completion: { (url, er) in
if er != nil{
print(er!.localizedDescription)
}
if let url = url
{
let userInfo: [String: Any] = ["uid": user.uid,"E-mail":self.emailfield.text,"username": self.usernamefield.text,"urlToImage": url.absoluteString]
self.ref.child("users").child(user.uid).setValue(userInfo)
let vc = UIStoryboard(name: "Main",bundle:nil).instantiateViewController(withIdentifier: "homeview")
self.present(vc,animated:true,completion:nil)
}
})
})
uploadTask.resume()
}
})
}
Your question is quite broad and actually covers a few different questions. Really, you should break the problem down and only post a question for each, but I will give you some guidance.
How to select multiple images using a UIImagePickerController - Basically you can't, you either need to use a library or do your own implementation using the PhotoLibrary
How to upload an image to Firebase should be fairly straight forward.
Multiple uploads can be a bit more complex. You could use a NSOperationQueue to manage a queue of items to process and specify how many to handle at once, you could use a SerialQueue to process items one at a time or a DispatchQueue to fire all of the requests at once and it will let you know when it finishes. Once you reach this point, firstly give it a try, look into the mentioned methods. If you get stuck, raise another question and explain your approach, how you want it to work and what is going wrong.
This other answer may help with the multiple uploads, if not have a look for Grand Central Dispatch online or check here

data not showing up in firebase database

im attempting to add user data via a create account view controller which contains all UITextFields (password, confirm password, first name, last name, phone number). when the create account button is tapped, the users email shows up in the authentication section on the firebase website but the user information from the first name, last name and phone number text fields are not passed into the database. I'm new to iOS development and have never used firebase so im unsure what the issue is. the app runs without crashing.
below is my Create Account view controller
thanks in advance
import UIKit
import FirebaseAuth
import QuartzCore
import FirebaseDatabase
import Firebase
class CreateAccount: UIViewController {
var refUsers: DatabaseReference!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var confirmPasswordTextField: UITextField!
#IBOutlet weak var firstNameTextField: UITextField!
#IBOutlet weak var lastNameTextField: UITextField!
#IBOutlet weak var phoneNumberTextField: UITextField!
#IBOutlet weak var alreadyHaveAccountLabel: UILabel!
#IBAction func loginButtonTapped(_ sender: Any) {
performSegue(withIdentifier: "showLoginScreen", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
self.refUsers = Database.database().reference().child("Users");
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
if Auth.auth().currentUser != nil {
print("success")
self.presentMainScreen()
}
}
#IBAction func createAccountTapped(_ sender: Any) {
if let email = emailTextField.text, let password = passwordTextField.text {
Auth.auth().createUser(withEmail: email, password: password, completion:{ user, error in
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
} else {
self.addUser()
print("this is the first name:", self.firstNameTextField.text!)
print("this is the last name:", self.lastNameTextField.text!)
print("this is the phone number" , self.phoneNumberTextField.text!)
print("success")
self.presentMainScreen()
}
})
}
}
func addUser(){
let key = refUsers.childByAutoId().key
let user = ["id":key,
"FirstName":firstNameTextField.text! as String,
"LastName":lastNameTextField.text! as String,
"PhoneNumber":phoneNumberTextField.text! as String
]
refUsers.child(key).setValue(user)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
func presentMainScreen(){
let mainstoryboard = UIStoryboard(name: "Main", bundle: nil)
let mainTabController = mainstoryboard.instantiateViewController(withIdentifier: "MainTabController") as! MainTabController
mainTabController.selectedViewController = mainTabController.viewControllers?[0]
self.present(mainTabController, animated: true, completion: nil)
//let storyboard:UIStoryboard = UIStoryboard(name:"Main", bundle:nil)
//let loggedInVC:LoggedInVC = storyboard.instantiateViewController(withIdentifier: "LoggedInVC") as! LoggedInVC
//self.present(loggedInVC, animated: true, completion: nil)
}
}
Try this:
Instead of set value use update value
let childUpdates = ["/user/\(key)": user]
refUser.updateChildValues(childUpdates)
Hope this helps :)

How to call performSegueWithIdentifier in Swift

I have created a prepareForSegue method and I am trying to call it from a button that I created by using the performSegueWithIdentifier method. The app is crashing when I load the simulator and it's not getting me a complete error message. Can someone please lead me in the right direction?
import Foundation
import UIKit
import Alamofire
import FBSDKCoreKit
import FBSDKShareKit
import FBSDKLoginKit
class PageContentViewController: UIViewController {
#IBOutlet weak var logoImageView: UIImageView!
#IBOutlet weak var contentLabel: UILabel!
#IBOutlet weak var backgroundImageView: UIImageView!
#IBOutlet weak var pageControl: UIPageControl!
#IBOutlet weak var facebookButton: UIButton!
var index : Int = 0
var logoFile: String = ""
var content: String = ""
var backgroundFile: String = ""
let facebookReadPermissions = ["public_profile", "email", "user_friends"]
override func viewDidLoad() {
super.viewDidLoad()
pageControl.currentPage = index
facebookButton.hidden = (index == 3 ) ? false : true
pageControl.hidden = (index == 3) ? true: false
logoImageView.image = UIImage(named: logoFile)
contentLabel.text = content
backgroundImageView.image = UIImage(named: backgroundFile)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let destinationController = segue.destinationViewController as? PaymentSubViewController
where segue.identifier == "payment" {
// Do something with `destinationController`
}
}
#IBAction func test(sender: AnyObject) {
self.performSegueWithIdentifier("payment", sender: self)
}
#IBAction func fbTouched(sender: AnyObject) {
FBSDKLoginManager().logInWithReadPermissions(self.facebookReadPermissions, handler: { (result:FBSDKLoginManagerLoginResult!, error:NSError!) -> Void in
if error != nil {
//According to Facebook:
//Errors will rarely occur in the typical login flow because the login dialog
//presented by Facebook via single sign on will guide the users to resolve any errors.
// Process error
FBSDKLoginManager().logOut()
} else if result.isCancelled {
// Handle cancellations
FBSDKLoginManager().logOut()
} else {
let fbToken = result.token.tokenString
Alamofire.request(Router.FacebookAuth(fbToken)).validate(statusCode: 200 ..< 300).responseJSON(completionHandler: { (request, response, JSON, error) in
if let json = JSON as? Dictionary<String, AnyObject> {
if let token = json["token"] as? String {
Router.OAuthToken = token
self.performSegueWithIdentifier("showHomeFeed", sender: self)
}
}
})
}
})
}
}
Because you are force unwrapping the destinationViewController using as!, if that value is nil or not a PaymentSubViewController, the app will crash.
The better way to implement this is with an optional binding (if let) and a conditional downcast (as?):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let destinationController = segue.destinationViewController as? PaymentSubViewController
where segue.identifier == "payment" {
// Do something with `destinationController`
}
}
Of course, that'll stop the crash but won't answer the question of why segue.destinationViewController is nil or of another type. Make sure that you segue is configured properly in interface builder and that the destination view controller actually has segue.destinationViewController for its Class value in the identity inspector tab.
I had a map object on the storyboard and I did not add an outlet for the object which was creating an error message.

Resources