How can I get hundredths place instead of tenths place in output - swift

When I enter an amount in the text field I get in total the amount in tenths place, so how can I get hundredths place instead of tenths place?
Also how can I get the tip percentage label an integer instead of a decimal?
import UIKit
class ViewController: UIViewController, SettingsDelegate {
//Inputs
#IBOutlet weak var amountTextField: UITextField!
//Labels
#IBOutlet weak var TipPercentageLabel: UILabel!
#IBOutlet weak var numberOfPersonLabel: UILabel!
#IBOutlet weak var tipAmountLabel: UILabel!
#IBOutlet weak var totalBillLabel: UILabel!
#IBOutlet weak var billPerPersonLabel: UILabel!
//Slider & Stepper
#IBOutlet weak var tipSlider: UISlider!
#IBOutlet weak var personsStepper: UIStepper!
//Variables
var tipPercentage : Double = NSUserDefaults.standardUserDefaults().doubleForKey("DefaultTipRate") ?? 0.20
var numberOfPerson:Int = 1
let numberFormatter:NSNumberFormatter = NSNumberFormatter()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tipAmountLabel.text = "$0.00"
totalBillLabel.text = "Bill Total"
billPerPersonLabel.text = "$0.00"
numberOfPersonLabel.text = "1"
self.amountTextField.becomeFirstResponder()
print("DefaultTipRate")
let tipPercentage : Double = NSUserDefaults.standardUserDefaults().doubleForKey("DefaultTipRate")
TipPercentageLabel.text = self.numberFormatter.stringFromNumber(tipPercentage)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setupContainer() {
tipSlider.minimumValue = 0
tipSlider.maximumValue = 100
tipSlider.value = 20
tipSlider.addTarget(self, action: "sliderTipChanged:", forControlEvents: .ValueChanged)
personsStepper.minimumValue = 1
personsStepper.maximumValue = 30
personsStepper.value = 1
personsStepper.addTarget(self, action: "sliderPersonChanged:", forControlEvents: .ValueChanged)
amountTextField.text = ""
refreshCalculation()
}
#IBAction func OnEditingFieldBill(sender: AnyObject) {
refreshCalculation()
}
func refreshCalculation() {
numberFormatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
if let amount = numberFormatter.numberFromString(amountTextField.text!) as? Double {
let tipAmount = amount * tipPercentage
let totalBill = amount + tipAmount
let billPerPerson = totalBill / Double(numberOfPerson)
numberFormatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
tipAmountLabel.text = numberFormatter.stringFromNumber(tipAmount)
totalBillLabel.text = numberFormatter.stringFromNumber(totalBill)
billPerPersonLabel.text = numberFormatter.stringFromNumber(billPerPerson)
} else {
tipAmountLabel.text = "-"
totalBillLabel.text = "-"
billPerPersonLabel.text = "-"
}
numberFormatter.numberStyle = NSNumberFormatterStyle.PercentStyle
numberFormatter.minimumFractionDigits = 2
numberFormatter.maximumFractionDigits = 2
TipPercentageLabel.text = String(format: "%.0f%%", tipPercentage)
numberOfPersonLabel.text = "\(numberOfPerson)"
}
#IBAction func sliderTipChanged(sender: AnyObject) {
tipPercentage = Double(round(tipSlider.value)) / 100
refreshCalculation()
}
#IBAction func StepperPersonChanged(sender: AnyObject) {
numberOfPerson = Int(round(personsStepper.value))
refreshCalculation()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let SettingsViewController = segue.destinationViewController as? SettingsViewController {
SettingsViewController.delegate = self
refreshCalculation()
}
}
func tipPercentageChanged(newValue: Double) {
TipPercentageLabel.text = "\(newValue)%"
tipPercentage = newValue
refreshCalculation()
}
SETTINGS VIEW CODE
import UIKit
protocol SettingsDelegate{
func tipPercentageChanged(newValue : Double)
}
class SettingsViewController: UIViewController {
#IBOutlet weak var tipControl: UISegmentedControl!
var tipRates:Double?
var destName : String!
var delegate :SettingsDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func changeValue(sender: UISegmentedControl) {
var tipRate = [0.05, 0.10, 0.15, 0.20, 0.25, 0.30]
tipRates = (tipRate[tipControl.selectedSegmentIndex])
delegate?.tipPercentageChanged(tipRates!); print("(tipRates)")
NSUserDefaults.standardUserDefaults().setDouble(tipRates!, forKey: "DefaultTipRate")
NSUserDefaults.standardUserDefaults().synchronize()
}
}

Since you are using NSNumberFormatter, set maximumFractionDigits and minimumFractionDigits properties to 2:
let numberFormatter = NSNumberFormatter()
numberFormatter.maximumFractionDigits = 2
numberFormatter.minimumFractionDigits = 2
let str = numberFormatter.stringFromNumber(14.7) // "14.70"
Alternatively, you could use the String(format:) constructor:
let str = String(format: "%.2f", 14.7) // "14.70"
For your tip percentage, since you are storing it as a decimal percentage, you can do:
let tipPercentage: Double = 0.17
TipPercentageLabel.text = String(format: "%.0f%%", tipPercentage * 100) // "17%"

Related

Sigbart error during prepare for segue/unwind segue

I have an app where it is a marketplace and when you click on a product, it opens a detail view controller passing the data to display on the DetailVC. Additionally, inside the DetailVC, if you click on a button to claim the product, it segues to another VC to finalize the transaction.
In the DetailVC, there is a back button which is an unwind segue back to the main marketplace VC. Inside the TransactionVC, there is a cancel button which takes you back to the DetailVC.
When I am clicking the backButton in the DetailVC to take me back to the main market VC but I am getting a SIGBART Error and this :
020-07-15 09:05:23.707490-0500 evolutionatx[707:141952] Could not cast value of type 'evolutionatx.MarketplaceViewController' (0x1032c7868) to 'evolutionatx.PopUpPurchaseViewController' (0x1032c7ba8).
Here is the code for the DetailVC
import UIKit
import iCarousel
import CoreData
class MarketDetailViewController: UIViewController, UIScrollViewDelegate, iCarouselDelegate, iCarouselDataSource {
var productImageArray = [UIImage]()
var productVideo = String()
var pointsToPurchase = String()
var productName = String()
var productDescription = String()
var companyLogo = UIImage()
var companyWebsite = String()
var additionalProductImage = [UIImage]()
var companyName = String()
var promoCODE = String()
var buyLink = String()
var slides:[Slide] = [];
//IB
#IBOutlet weak var productNameLabel: UILabel!
#IBOutlet weak var productPriceLabel: UILabel!
#IBOutlet weak var productDescLabel: UILabel!
#IBOutlet weak var claimButton: UIButton!
#IBOutlet weak var imgScrollView: UIScrollView!
#IBOutlet weak var websiteButton: UIButton!
#IBOutlet weak var pageControl: UIPageControl!
#IBOutlet weak var logoDisplay: UIImageView!
#IBOutlet weak var carouselView: iCarousel!
#IBOutlet weak var otherProductslabe: UILabel!
var carouselImages = [UIImage]()
var evoCoin = Int()
override func awakeFromNib() {
super.awakeFromNib()
carouselImages = productImageArray
}
override func viewDidLoad() {
super.viewDidLoad()
valueSetter()
imgScrollView.delegate = self
slides = createSlides()
setupSlideScrollView(slides: slides)
pageControl.numberOfPages = slides.count
pageControl.currentPage = 0
view.bringSubviewToFront(pageControl)
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
pageControl.currentPage = Int(pageIndex)
let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x
// vertical
let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
let currentVerticalOffset: CGFloat = scrollView.contentOffset.y
let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset
}
#IBAction func claimProduct(_ sender: Any) {
print("tap rec")
claimProductandPurchase()
}
func claimProductandPurchase(){
evoCOiner()
if(evoCoin >= Int(pointsToPurchase)!){
print("Transaction Successful")
performSegue(withIdentifier: "proceedQuestion", sender: self)
}
else{
showToast(controller: self, message: "Insufficient EvoCoins", seconds: 0.5)
}
}
func showToast(controller: UIViewController, message : String, seconds: Double) {
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
alert.view.backgroundColor = UIColor.black
alert.view.alpha = 0.6
alert.view.layer.cornerRadius = 15
controller.present(alert, animated: true)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds) {
alert.dismiss(animated: true)
}
}
func evoCoiner(){
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "EvoCoins")
request.returnsObjectsAsFaults = false
do{
let result = try context.fetch(request)
for data in result as! [NSManagedObject]
{
evoCoin = data.value(forKey: "evoCoins") as! Int
}
}catch{
print("Failed")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let detailController = segue.destination as! PopUpPurchaseViewController
detailController.ppromo = promoCODE
detailController.link = buyLink
detailController.coinToPurchase = Int(pointsToPurchase)!
}
//This is the unwind used by the transaction back button
#IBAction func unwindToItem(segue: UIStoryboardSegue) {
}
}
Here is the code in the transaction VC
import UIKit
import AMTabView
import CoreData
class MarketplaceViewController: UIViewController, TabItem {
#IBOutlet weak var sView: UIView!
#IBOutlet weak var evoCoinLabe: UILabel!
//For the sake of simplicity I only kept the Unwind functions
//MARK: - UNWIND FUNCTIONS
#IBAction func unwindToMainMarketView(segue: UIStoryboardSegue) {
}
}
How can I fix this error?
Please advise if my question was not clear or properly phrased (if so, sorry I am pretty new to all of this)
As #matt already said in his comment and the error clearly states, you cannot cast a MarketplaceViewController to a PopUpPurchaseViewController.
Furthermore instead of doing a forced cast, always look for a safe one like below. Doing so will prevent crashes.
if let detailController = segue.destination as? PopUpPurchaseViewController {
...
}
else {
// log failed to cast
}

Swift: Why can I pass info from one IBAction to another, but not to a function

I am trying to get the values for splitValue and tipPercent into the getSettings() at the bottom. Why can I get the values for both of those in the IBAction calculatePressed, but when I try to get the values into the function the value is nil. I am sooo confused. Thank you for the help!
#IBOutlet weak var billTextField: UITextField!
#IBOutlet weak var zeroPctButton: UIButton!
#IBOutlet weak var tenPctButton: UIButton!
#IBOutlet weak var twentyPctButton: UIButton!
#IBOutlet weak var splitNumberLabel: UILabel!
var tipChosen = ""
var totalPerPerson = ""
var tipPercent = ""
var splitValue = ""
#IBAction func tipChanged(_ sender: UIButton) {
tipPercent = sender.currentTitle!
if sender.isSelected == true {
return
}
zeroPctButton.isSelected = false
tenPctButton.isSelected = false
twentyPctButton.isSelected = false
sender.isSelected = true
if sender.currentTitle == "0%" {
tipChosen = "0.00"
} else if sender.currentTitle == "10%" {
tipChosen = "0.10"
} else if sender.currentTitle == "20%" {
tipChosen = "0.20"
}
billTextField.endEditing(true)
}
#IBAction func stepperValueChanged(_ sender: UIStepper) {
splitValue = String(Int(sender.value))
splitNumberLabel.text = String(Int(sender.value))
}
#IBAction func calculatePressed(_ sender: UIButton) {
let bill = Float(billTextField.text!)!
let tip = Float(tipChosen)!
let tax = bill * tip
let splitNumber = Float(splitNumberLabel.text!)
let total = (bill + tax) / Float(splitNumber!)
totalPerPerson = "$\(String(format: "%.2f", total))"
performSegue(withIdentifier: "goToTotal", sender: self)
}
func getSettings() -> String {
return "Split between \(splitValue) people, with a \(tipPercent) tip."
}
Ok, sorry it took me a bit, but I finally think I understand what I did.
class CalculatorViewController: UIViewController {
var tip = 0.0
var finalBill = ""
var split = 2
#IBOutlet weak var billTextField: UITextField!
#IBOutlet weak var zeroPctButton: UIButton!
#IBOutlet weak var tenPctButton: UIButton!
#IBOutlet weak var twentyPctButton: UIButton!
#IBOutlet weak var splitNumberLabel: UILabel!
#IBAction func tipChanged(_ sender: UIButton) {
if sender.isSelected == false {
sender.isSelected = false
} else if sender.isSelected == true {
sender.isSelected = true
}
zeroPctButton.isSelected = false
tenPctButton.isSelected = false
twentyPctButton.isSelected = false
sender.isSelected = true
billTextField.endEditing(true)
}
#IBAction func stepperValueChanged(_ sender: UIStepper) {
splitNumberLabel.text = Int(sender.value).description
}
#IBAction func calculatePressed(_ sender: UIButton) {
if zeroPctButton.isSelected == true {
tip = 0.0
} else if tenPctButton.isSelected == true {
tip = 0.1
} else if twentyPctButton.isSelected == true {
tip = 0.2
}
print(tip)
let bill = Double(billTextField.text!)
split = Int(Double(splitNumberLabel.text!)!)
if billTextField.text != "" {
let billWithTip = (bill! * tip) + bill!
let billWithTipSplit = billWithTip / Double(split)
finalBill = String(format: "%.2f", billWithTipSplit)
print(billWithTip)
}
self.performSegue(withIdentifier: "getResults", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "getResults" {
let destinationVC = segue.destination as! ResultsViewController
destinationVC.finalBill = finalBill
destinationVC.split = split
destinationVC.tip = tip
}
}
}
class ResultsViewController: UIViewController {
#IBOutlet weak var totalLabel: UILabel!
#IBOutlet weak var settingsLabel: UILabel!
var tip = 0.0
var split = 2
var finalBill = ""
override func viewDidLoad() {
super.viewDidLoad()
totalLabel.text = "$\(finalBill)"
settingsLabel.text = "Split between \(Int(split)) people, with a \(Int(tip * 100))% tip"
}
#IBAction func recalculatePressed(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}
I did what you suggested with the string and some minor calculations on the second view controller, changed the values of a few declared properties and got rid of the getSettings(). I was under the impression that I couldn't pass data without a return value from a function. Thank you for the help!

View Controller doesn't find a func member

I'm getting this error:
Value of type 'DiscountVC' has no member 'calculateTotal'. And I have no clue why. Basically, I'm trying to make this calculator:
It should work as soon as you insert any value on the discountTF. Also, I have some pre-discounted buttons that just edit the discount value. The subtotalLabel value comes from another ViewController. For testing purposes, I'm using an initial value of 999.9.
import UIKit
class DiscountVC: UIViewController {
#IBOutlet var numericKeyboardView: UIView!
#IBOutlet var subtotalLabel: UILabel!
#IBOutlet var discountTF: UITextField!
#IBOutlet var totalLabel: UILabel!
var subtotal : Double = 999.9
var discount : Double = 0.0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
addKeyboard(view: numericKeyboardView)
subtotal = 999.9
discount = 0.0
discountTF.addTarget(self, action: #selector(self.calculateTotal(_:)), for: UIControl.Event.editingChanged)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
func calculateTotal() {
let totalDouble = Double(subtotal) - Double(discountTF.text!)!
totalLabel.text = String(totalDouble)
}
func addKeyboard(view: UIView) {
let numericKeyboard = KeyboardVC(nibName: "NumericKeyboardVC", bundle: nil)
view.addSubview(numericKeyboard.view)
addChild(numericKeyboard)
}
#IBAction func fivePercentedButtonPressed(_ sender: Any) {
discount = Double(discountTF.text!)! * 0.05
discountTF.text = "\(discount)"
print(discount)
}
#IBAction func tenPercentButtonPressed(_ sender: Any) {
discount = Double(discountTF.text!)! * 0.1
discountTF.text = "\(discount)"
print(discount)
}
#IBAction func fifteenPercentButtonPressed(_ sender: Any) {
discount = Double(discountTF.text!)! * 0.15
discountTF.text = "\(discount)"
print(discount)
}
#IBAction func twentyPercentButtonPressed(_ sender: Any) {
discount = Double(discountTF.text!)! * 0.2
discountTF.text = "\(discount)"
print(discount)
}
#IBAction func goButton(_ sender: Any) {
}
}
Change to
#objc func calculateTotal(_ tex:UITextField){ --- }

Applying an NSTimer to a UILabel (Swift)

i'm quite new to using swift and i'm currently working on a small school project. However, one function i cant seem to work out is how to make an NSTimer change the text in a UILabel after a certain amount of time. I want to apply this function to a UILabel (cannotbuy) that was blank, and had just been changed to text displaying a message("you dont have enough points"), and i want this message to be removed and the UILabel to be blank again after a second or so. Can anyone help me? Thanks.
class Upgrades: UIViewController{
#IBOutlet weak var shprogresslabel: UILabel!
#IBOutlet weak var fsprogresslabel: UILabel!
#IBOutlet weak var shprogress: UIProgressView!
#IBOutlet weak var fsprogress: UIProgressView!
#IBOutlet weak var shbutton: UIButton!
#IBOutlet weak var fsbutton: UIButton!
#IBOutlet weak var storepoints: UILabel!
#IBOutlet weak var cannotbuy: UILabel!
#IBOutlet weak var label2: UILabel!
#IBOutlet weak var label1: UILabel!
var fsprice = Int()
var shprice = Int()
let defaults = NSUserDefaults.standardUserDefaults()
func updateProgress1(){
fsprogress.progress += 0.1
let fsprogressvalue = self.fsprogress.progress
fsprogresslabel.text = "\(fsprogressvalue * 100)%"
}
func updateProgress2(){
shprogress.progress += 0.2
let shprogressvalue = self.shprogress.progress
shprogresslabel.text = "\(shprogressvalue * 100)%"
}
#IBAction func button2(sender: AnyObject) {
if shprice <= 90{
if SharingManager.sharedInstance.totalscore >= shprice{
SharingManager.sharedInstance.shiphealth = SharingManager.sharedInstance.shiphealth + 1
SharingManager.sharedInstance.totalscore = SharingManager.sharedInstance.totalscore - fsprice
storepoints.text = String(SharingManager.sharedInstance.totalscore)
shprice = shprice + 20
print(shprice)
label2.text = ("\(shprice)")
defaults.setInteger(SharingManager.sharedInstance.shiphealth, forKey: "SharingManager.sharedInstance.shiphealth")
updateProgress2()
}else{
cannotbuy.text = "You dont have enough points"
}
}else{
cannotbuy.text = "You have purchased all the available upgrades for this"
}
}
#IBAction func button1(sender: AnyObject) {
if fsprice <= 100{
if SharingManager.sharedInstance.totalscore >= fsprice{
SharingManager.sharedInstance.bulletspeed = SharingManager.sharedInstance.bulletspeed - 0.15
SharingManager.sharedInstance.totalscore = SharingManager.sharedInstance.totalscore - fsprice
storepoints.text = String(SharingManager.sharedInstance.totalscore)
fsprice = fsprice + 10
print(fsprice)
label1.text = ("\(fsprice)")
defaults.setDouble(SharingManager.sharedInstance.bulletspeed, forKey: "SharingManager.sharedInstance.bulletspeed")
updateProgress1()
}else{
cannotbuy.text = "You dont have enough points"
}
}else{
cannotbuy.text = "You have purchased all the available upgrades for this"
}
}
override func viewDidLoad() {
if fsprice == 0{
fsprice = 10
}
if shprice == 0{
shprice = 10
}
if fsprice == 180{
fsbutton.enabled = false
}
if shprice == 100{
shbutton.enabled = false
}
storepoints.text = String(SharingManager.sharedInstance.totalscore)
label1.text = ("\(fsprice)")
label2.text = ("\(shprice)")
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
There are two ways for you to do this:
Using NSTimer:
#IBAction func button2(sender: AnyObject) {
...
cannotbuy.text = "You don't have enough points"
NSTimer.scheduledTimerWithTimeInterval(5, target: self, selector: #selector(ViewController.resetCannotBuy), userInfo: nil, repeats: false)
}
func resetCannotBuy() {
cannotbuy.text = ""
}
Using dispatch_after:
#IBAction func button2(sender: AnyObject) {
...
cannotbuy.text = "You don't have enough points"
let fiveSecondLater = dispatch_time(DISPATCH_TIME_NOW, 5 * Int64(NSEC_PER_SEC))
dispatch_after(fiveSecondLater, dispatch_get_main_queue()) {
self.cannotbuy.text = ""
}
}
NSEC_PER_SEC is the constant for nanosecond per second, which is equal to 1 billion.

UILabel Text Code

I am new to programming. Really new and am trying to get the "outputLabel" to fade in when I press the "quoteButtonTapped" button. I have tried to set the alpha to 0.0 and then with a delay to alpha 1.0 but
self.outputLabel.alpha does not work.
Wow! I am perhaps missing something really basic here but the "quoteButtonTapped" does select a random quotation from an array and it's reference label, but how can I get the label text to fade in?
I included code below:
class ViewController: UIViewController {
#IBOutlet weak var outputLabel: UILabel!
#IBOutlet weak var borderImage: UIImageView!
#IBOutlet weak var scrollViewWindow: UIScrollView!
#IBOutlet weak var referenceLabel: UILabel!
#IBAction func quoteButtonTapped(sender: AnyObject) {
scrollViewWindow.contentSize.height = 800
}
override func viewDidLoad() {
super.viewDidLoad()
}
func displayCurrentScripture() {
let range: UInt32 = UInt32(quotes.count)
let randomNumber = Int(arc4random_uniform(range))
let QuoteString = quotes.objectAtIndex(randomNumber)
let ReferenceString = references.objectAtIndex(randomNumber)
self.outputLabel.text = QuoteString as? String
self.referenceLabel.text = ReferenceString as? String
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
UILabel.referenceLabel..
}
displayCurrentScripture()
}
Try This :
override func viewDidLoad() {
super.viewDidLoad()
displayCurrentScripture();
}
func displayCurrentScripture() {
let range: UInt32 = UInt32(quotes.count)
let randomNumber = Int(arc4random_uniform(range))
let QuoteString = quotes.objectAtIndex(randomNumber)
let ReferenceString = references.objectAtIndex(randomNumber)
self.outputLabel.alpha = 0.0
self.referenceLabel.alpha = 0.0
self.outputLabel.text = QuoteString as? String
self.referenceLabel.text = ReferenceString as? String
UIView.animateWithDuration(0.2, animations: { () -> Void in
self.outputLabel.alpha = 1.0
self.referenceLabel.alpha = 1.0
});
}