1

Swift 2. I'm trying to use the answer of a label.text! to multiply again. The label is an optional but it has to be multiplied with a Double.

@IBOutlet weak var testLabel: UILabel!
@IBOutlet weak var first: UITextField!
@IBOutlet weak var second: UITextField!

func calculation1() {
let dfirst = Double(first.text!)
let dsecond = Double(second.text!)
if dfirst != nil && dsecond != nil {
let answerCal = ceil(dfirst! * dsecond!)
let numberFormatter = NSNumberFormatter()
numberFormatter.numberStyle = .DecimalStyle
testLabel.text = numberFormatter.stringFromNumber(answerCal)
}
}

Any help will be appreciated.

Vidal Singh
  • 123
  • 1
  • 6
  • What are you exactly trying to do? Im not sure I understand but ill do my best to help you. – brkr Sep 07 '16 at 08:06
  • The label ( testLabel.text ). In the last line, when it gets the answer from the 2 textFields, is prints as an optional like Optional("6"). I want the testLabel.text to be a Double at the end instead of an optional ( because when its an optional, the formula crashes if the label is over 1000, and I'm working with big numbers . Thanks. – Vidal Singh Sep 08 '16 at 19:37

1 Answers1

0

First of all, apologies as I've put this together on a tablet meaning I cannot access the code editor. However, here's my take on your problem:

@IBOutlet weak var testLabel: UILabel!
@IBOutlet weak var first: UITextField!
@IBOutlet weak var second: UITextField!

func calculation1() -> Void {
    // Check our two text fields contain text
    guard let _ = first.text,
          let _ = second.text else { return }
  c // Check that the text can be parsed as Doubles
  c guard let dfirst : Double = Double(first.text!),
    let dsecond : Double = Double(second.text!) else { return }

    // Now that we know we have two valid numbers, do the calculation
    let answerCal : Double = ceil(dfirst! * dsecond!)

    // Fetch a number formatter
    let numberFormatter : NSNumberFormatter = {
        let nF : NSNumberFormatter = NSNumberFormatter()
        nF.numberStyle = .DecimalStyle
        return nF
    }()
    // And update the text field with the answer if it produces a valid result
    if let answerText : String =     numberFormatter.stringFromNumber(answerCal) {
         testLabel.text = answerText
    }
}

You've got to be careful with UI elements where the user can theoretically type in anything and crash your app if you don't check it first. Hence the guard statements that will safely exit the method call if there is no text in the text fields or if those fields contain unusable text.

The reason you're getting an Optional back from your number formatter is because there is no guarantee that the formatter will be able to give you a valid string. Therefore you'll see that I've explicitly checked that the numbe formatter does generate a non-nil result before trying to update the text field.

(Note - I appreciate the closure for the number formatter is technically surplus to requirements but I find it clearer sometimes when configuring an object.)

UPDATE:

Vidal - did you try the code I sent you? I've quickly knocked up the following which is based on what I put together last night. It is obviously crude but shows that the methodology I suggested works fine, unless I'm missing something. The only issue I can think of is that you've done something in interface builder which I'm unaware of. Hope that helps!

import UIKit

class ViewController: UIViewController {

    var calculatorView : UIView!
    var textFieldOne : UITextField!
    var textFieldTwo : UITextField!
    var calButton : UIButton!
    var answer : UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.calculatorView = {
                let cV : UIView = UIView(frame: CGRect(origin: CGPointZero, size: CGSizeMake(400, 400)))
            cV.backgroundColor = UIColor.redColor()

            func buildTextField() -> UITextField {
                let tF : UITextField = UITextField()
                tF.backgroundColor = UIColor.whiteColor()
                tF.textColor = UIColor.blackColor()
                tF.placeholder = "Please enter number"
                return tF
            }

            self.textFieldOne = buildTextField()
            self.textFieldTwo = buildTextField()
            self.textFieldOne.frame = CGRect(origin: CGPointMake(20, 20), size: CGSizeMake(160, 50))
            self.textFieldTwo.frame = CGRect(origin: CGPointMake(220, 20), size: CGSizeMake(160, 50))

            self.calButton = {
                let cB : UIButton = UIButton()
                cB.setTitle("Calculate", forState: .Normal)
                cB.frame = CGRect(origin: CGPointMake(20, 80), size: CGSizeMake(360, 50))
                cB.addTarget(self, action: #selector(self.getAnswer), forControlEvents: UIControlEvents.TouchUpInside)
                return cB
            }()

            self.answer = {
                let a : UILabel = UILabel()
                a.backgroundColor = UIColor.blueColor()
                a.textColor = UIColor.whiteColor()
                a.frame = CGRect(origin: CGPointMake(20, 140), size: CGSizeMake(360, 50))
                return a
            }()

            cV.addSubview(textFieldOne)
            cV.addSubview(textFieldTwo)
            cV.addSubview(calButton)
            cV.addSubview(answer)

            return cV
        }()

        self.view.addSubview(calculatorView)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func getAnswer() -> Void {
        // Check our two text fields contain text
        guard let _ = self.textFieldOne.text,
              let _ = self.textFieldTwo.text else { return }
        // Check that the text can be parsed as Doubles
        guard let dfirst : Double = Double(self.textFieldOne.text!),
              let dsecond : Double = Double(self.textFieldTwo.text!) else { return }

        // Now that we know we have two valid numbers, do the calculation
        let answerCal : Double = ceil(dfirst * dsecond)

        // Fetch a number formatter
        let numberFormatter : NSNumberFormatter = {
            let nF : NSNumberFormatter = NSNumberFormatter()
            nF.numberStyle = .DecimalStyle
            return nF
        }()
        // And update the text field with the answer if it produces a valid result
        if let answerText : String = numberFormatter.stringFromNumber(answerCal) {
            self.answer.text = answerText
        }
    }
}
Marcus
  • 2,153
  • 2
  • 13
  • 21
  • I'm using a custom keyboard that will only have digits and a "." . I want to take the answer of the testlabel.text and use it in another func. e.g. If the testlabel.text is "1200", I want to have "1200 x 3%". But the compiler is telling me testlabel.text is a double. thanks. – Vidal Singh Sep 12 '16 at 16:13
  • ok, at the last line ( "self.answer.text = answerText"). This links the label to the String. But lets say I want to create a new func and take "answer" which is the label and do an additional multiplication, whats the procedure? Why I'm stuck,,, the label is an optional and it doesn't play well with another func that has doubles or strings ( even if I do "let doubleConvert = Double(answer)" it gives an error. thanks. – Vidal Singh Sep 13 '16 at 03:13
  • ok, I got it to work let percent3:Double = 1.03 @IBAction func threePercent(sender: AnyObject) { if let cost = Double(testLabel.text!) { let stringConv = "\(cost)" var doubleValueFromString = Double((stringConv as NSString).doubleValue) doubleValueFromString = doubleValueFromString * percent3 let DoubleToString = "\(doubleValueFromString)" testLabel.text = DoubleToString } else { print("Not a valid number: \(testLabel.text!)") } } – Vidal Singh Sep 13 '16 at 04:51
  • the text isnt showing up as code, but basically I had to unwarp the label.text by setting it first as a double, then converting it as a string, then using Double((stringConv as NSString).doubleValue) This converts back the string to a double, then I did the multiplication, then when I got the answer, I converted it back to a string and then added it to the label.text. thanks again! – Vidal Singh Sep 13 '16 at 04:53