1

In my application I have a textbox that should be filled with a Double and the number should be saved into a variable but there's an error. I dragged and dropped the textbox into ViewController.swift so it should be linked. I created a @IBOutlet. I called the textbox mmolText and the variable mmol. I tried something like: var mmol = mmolText.text but it shows an error:

'ViewController.Type' does not have a member named 'mmolText'.

What's the problem? How can I solve it? Besides the type of the content of the textbox is a string but I should convert it into Double.

screenshot

Here the code of ViewController.swift is:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var mmolText: UITextField!
    var mmol = mmolText.text
    @IBOutlet weak var mmolLabel: UILabel!
    @IBOutlet weak var mgLabel: UILabel!
    @IBAction func convertBM(sender: AnyObject) {

    }
    override func viewDidLoad() {
        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.
    }


}
Fabio
  • 2,074
  • 2
  • 24
  • 38

3 Answers3

2

It seems like we probably simply want mmol to exist as a convenient way for getting the text property out of the mmolText textfield, right? So why not use a computed property:

var mmol: String {
    get {
        return mmolText.text ?? ""
    }
    set {
        mmolText.text = newValue
    }
}

The get makes use of the nil coalescing operator. UITextField's text property hasn't been updated with the Objective-C nullability annotations yet, so we need to handle the case of it potentially returning nil.

If we want this to be readonly, we can simply omit the set part.


If we want this as a Double, we can modify the above computed property to look more like this:

var mmol: Double {
    get {
        return ((mmolText.text ?? "0") as NSString).doubleValue
    }
    set {
        mmolText.text = String("%f", newValue)
    }
}

And again, if we want this to be readonly, we can simply omit the set half. And of course, the format string can be played around with to get the string version of the double to show up exactly as you intend when using this set method.

Community
  • 1
  • 1
nhgrif
  • 61,578
  • 25
  • 134
  • 173
  • Thanks for your answer. I just started learning iOS development. Yes, It can be just "readonly" so we can avoid to use "set". Anyway isn't it possible to use just the "=" operator instead of "get"? And just use an "if" condition for testing wether the textbox is empty or not? Since I'm new to iOS development I'd prefer the easiest solution. – Fabio May 18 '15 at 00:15
  • To make it `readonly`, just delete the `set` part. You can use the `=` operator, but now you have to set it with the `=` operator **every**time the textbox changes. Using this approach, the `mmol` property just fetches from the textbox any time it is accessede. There's a way to write this using an `if` condition, but there's nothing complicated about `??`. This **is** the *easiest* solution. It's also the *best* solution. – nhgrif May 18 '15 at 00:17
  • 1
    @Fabio You can read up on Swift's nil coalescing operator (`??`) [here](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-ID72) in the **Basic Operators** section of the Swift online documentation. – nhgrif May 18 '15 at 00:20
  • 1
    Thank you again @nhgrif. I just asked because I've learnt the "=" but I didn't encounter "get" yet so it was easier for me to use a method that I already know, anyway I understand the logic of your code and it seems better. Besides it isn't hard after all. – Fabio May 18 '15 at 00:21
  • Thank you for pointing me to the relevant Swift documentation. – Fabio May 18 '15 at 00:22
1
class ViewController: UIViewController {

    @IBOutlet weak var mmolText: UITextField!

    var mmol: String!

    override func viewDidLoad() {
        super.viewDidLoad()

        mmol = mmolText.text
    }
}

This way it works. I can remember something like because at that stage, the properties can exist. Which means, it can be there or it isn't. That's why you can't do it like that.

Don't pin me on this explanation though, I'm not very sure.

Eendje
  • 8,815
  • 1
  • 29
  • 31
  • Thank you. I added "var mmol: String!" as you suggested, then I added "mmol = mmolText.text" inside "@IBAction func convertBM(sender: AnyObject) {}" because I want it to occur when the button is pressed. Then I used the println() function for checking the value of the variable. It works now, though the variable type is String. I would like to input numbers with decimals so i'd like to convert the String into a Double. I know for integers there's the method .toInt(), how can I do for Doubles? – Fabio May 17 '15 at 23:56
  • I'm downvoting because this sort of answer encourages a question days/weeks/months/whenever from now about "unexpectedly incountered nil while unwrapping an optional". There's a time and a place for implicitly unwrapped optionals and *this* is definitely not it. Besides, as my answer outlines, there's a **way** better approach to this problem. – nhgrif May 18 '15 at 00:14
  • @nhgrif Like I said, it's opinion based. It's not up to you to decide what's right and whatnot. Sure, I agree it's not the best place to use it. A simple comment would be suffice and I would have changed it **and** keeping it in mind for the next time I try to help someone. Whether there are better ways to solve it is even more of an opinion. I'm pretty sure SO isn't a place for opinions. – Eendje May 18 '15 at 00:16
  • If you want to argue about how I should be using my downvotes, you're welcome to take it up on the meta, or invite me to a chat. – nhgrif May 18 '15 at 00:18
0

mmolText is a property on self. You can't refer to it there because self has not been initialized yet.

You'll have to assign it within awakeFromNib, viewDidLoad, etc.

Aaron Brager
  • 65,323
  • 19
  • 161
  • 287