I am brand new to Swift and Xcode and I am trying to build a financial calculator for Mac and I have encountered two issues.
The first issue is that in my code, it says that I initialized a value, but never used it. I believe that I have actually done that, but I keep getting the error. Here is my entire code for the class I'm working on:
import Cocoa
class PresentValueController: NSViewController {
#IBOutlet weak var answer_label: NSTextField!
#IBOutlet weak var payment_field: NSTextField!
#IBOutlet weak var rate_field: NSTextField!
#IBOutlet weak var periods_field: NSTextField!
#IBOutlet weak var compounding_popup: NSPopUpButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
#IBAction func popupValueChanged(_ sender: NSPopUpButton) {
let rate = (rate_field.integerValue)/sender.selectedTag()
return
}
#IBAction func calculate_button(_ sender: Any) {
let payment = (payment_field.integerValue)
let present_value = (payment / (1 + rate)^12)
answer_label.stringValue = "$\(present_value)"
}
}
As you can see, I have defined rate and tried to use it, but I keep getting the error.
My next question has to do with aesthetics. This is what I want my output to look like, but this is what ends up happening when I comment out the errors and run the code. Could I please get some help?
Thanks!!!
The problem is here
let rate = (rate_field.integerValue)/sender.selectedTag()
you don't use , you may think it's visible inside the other method but it's not , also remove the return
//
#IBAction func calculate_button(_ sender: Any) {
let rate = (rate_field.integerValue)/ popButton.selectedTag()
let payment = (payment_field.integerValue)
let present_value = (payment / (1 + rate)^12)
answer_label.stringValue = "$\(present_value)"
}
and declare
#IBOutlet weak var popButton: NSPopUpButton!
if it's not already
#IBOutlet weak var compounding_popup: NSPopUpButton!
Your rate variable is local to popupValueChanged(_:), and your reference to rate in calculate_button(_:) is a reference to an undefined variable.
You could save rate as an instance variable of your PresentValueController objects, but I would advise against it, because you would be duplicating data, and it's easy for it to go out of sync as the complexity of your app grows.
Instead, I recommend you just compute the rate within your calculate_button(_:) function, and drop the popupValueChanged(_:) function completely:
class PresentValueController: NSViewController {
#IBOutlet weak var answerLabel: NSTextField!
#IBOutlet weak var paymentField: NSTextField!
#IBOutlet weak var rateField: NSTextField!
#IBOutlet weak var periodsField: NSTextField!
#IBOutlet weak var compoundingPopup: NSPopUpButton!
#IBAction func calculateButton(_ sender: NSButton) {
let rate = rateField.integerValue / sender.selectedTag()
let payment = paymentField.doubleValue
let presentValue = payment / pow(1 + Double(rate), 12)
let formatter: NumberFormatter = {
let f = NumberFormatter()
f.locale = NSLocale.current
f.numberStyle = .currency
return f
}()
answerLabel.stringValue = formatter.string(from: NSNumber(value: presentValue))!
}
}
You need to understand the concepts of scope and local variables.
A variable (or a let constant) you define inside a function only exists inside the function. (For the rest of this post I'm going to use the term "variable", "immutable variable" and "let constant" interchangeably, even though that's a bit sloppy.)
Your function popupValueChanged() creates a local variable rate that only exists inside the function. As soon as you exit the function, the local variables you define inside the function go out of scope and cease to exist.
Based on the code you posted I would expect your function calculate_button() to have another error about an undefined expression rate.
Consider this code:
class AClass {
let rate = 3
func foo() {
let rate = 6
print("inside function, rate =", rate)
print("inside function, self.rate = ", self.rate)
}
}
let anObject = AClass()
anObject.foo()
print("outside function, anObject.rate = ", anObject.rate)
print("rate =", rate) //This will give an error.
(pretend it's entered into a playground)
The code will do the following:
Create an instance of AClass. The initialization of the AClass object will create an immutable instance variable rate with a value of 3.
Then we call the AClass object's foo() method, which defines a different, local variable, also named rate, and assigns the value 6 to that local variable.
The output of that code will be
inside function, rate = 6
inside function, anObject.rate = 3
outside function, anObject.rate = 3
Inside the function, the local variable rate hides the instance variable rate, so referring to rate inside the function refers to the local immutable variable. Since there are 2 different variables named rate defined at different scopes, we have to use self.rate to refer to the instance variable rate inside the function.
Outside the foo() function the function's local variable rate no longer exists so rate refers to the instance variable rate, who's value has always been 3.
The line:
print("rate =", rate) //This will give an error.
Will give a compile error since outside the function there is no variable at that scope with the name rate.
Related
Learning swift but a little confused as to the below. I have struct created and instantiated, but I cannot access the property of the struct inside of my view controller class unless the struct is inside one my my class methods. See below, why would this be the case?
class WeatherViewController: UIViewController, UITextFieldDelegate, WeatherManagerDelegate {
//create new weather manager struct
var weatherManager = WeatherManager()
//can't access property here, but I can access it inside of functions within this
//class, see below under viewDidLoad()
weatherManager.delegate = self
#IBOutlet weak var conditionImageView: UIImageView!
#IBOutlet weak var temperatureLabel: UILabel!
#IBOutlet weak var cityLabel: UILabel!
#IBOutlet weak var searchTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
//can access property here
weatherManager.delegate = self
}
The problem isn't where the WeatherManager object is declared and created. The problem is that this line:
weatherManager.delegate = self
is a command (technically a statement), not a declaration. (The line above it is a declaration, one that happens to also set the weatherManager property's default value). This is a pretty universal rule in most languages in the C++/Java family -- see short C++ example below. A command (statement) must be inside some method (or function, in non-OOP programming), not at the top level of a file or class. In Swift, actions like setting an object's delegate would typically go in the view controller's viewDidLoad.
int x = 0; // legal: declaring a global variable
x = x + 42; // NOT legal: this is a statement, not a declaraiton
int main()
{
x = x + 42; // legal: now we're inside a function
return 0;
}
I am beginner of swift. I tried to use array's append method in my code but it doesn't work. How should I implement the array correctly?
The error messages:
Swift Compiler Error Group
ViewController.swift:16:5: Expected declaration
ViewController.swift:11:7: In declaration of 'ViewController'
I tried to use array's append method in my code but it doesn't work.
import UIKit
class ViewController: UIViewController { //Error msg: In declaration of 'ViewController'
#IBOutlet weak var dice: UIImageView!
#IBOutlet weak var dice2: UIImageView!
var dices : [String] = []
dices.append("Hi") //Error: Expected declaration
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func rollPressed(_ sender: UIButton) {
dice.image = UIImage(named: "dice3")
}
}
I expect I can add "hi" into the array dices.
You should call the append inside a function after the vc is fully initated
class ViewController: UIViewController { //Error msg: In declaration of 'ViewController'
#IBOutlet weak var dice: UIImageView!
#IBOutlet weak var dice2: UIImageView!
var dices : [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
dices.append("Hi") // e.x here
}
#IBAction func rollPressed(_ sender: UIButton) {
dice.image = UIImage(named: "dice3")
}
}
Or replace
var dices : [String] = []
with
var dices = ["Hi"]
SH_Khan is right. I'll explain why though.
When defining a class, the first level of indentation is only for its methods and properties, aka func, var, and let. (You can also define other classes/structs/enums in there too)
Calling those functions or system functions like Array.append() or print("dog sweat") must happen inside of another function. The reason why is that your application's live logic is literally just functions all the way down. No function gets called unless it's inside of another function first. (The only exceptions are Swift's quick and dirty initializations like setting a default value to a var outside of an init() { } or another function.)
A dog doesn't wake up from its nap unless you make some noise. It won't do it on its own. (crappy metaphor, but yeah)
I hope that made any sense.
Is it possible to use a variable in a label name.
For example, my label is called button1text and I have a variable var x = 1.
Is there a way to do thisbutton(x)text?
No. You can not have variable name in identifier.
Variable names are evaluated at compile time, so no, it's not possible (at runtime).
Alternatively use an array or assign tags to the labels and get the label with viewWithTag
You can use reflection with Mirror. The capabilities are very limited in the context you want but you can try something like:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var button1: UIButton!
#IBOutlet weak var button2: UIButton!
#IBOutlet weak var button3: UIButton!
#IBAction func didTapGoButton(_ sender: Any) {
let mirror = Mirror(reflecting: self)
for child in mirror.children {
if let v = child.label, v == "button2" {
(child.value as! UIButton).titleLabel?.text = "changed"
}
}
}
}
I am currently making a calculator, and I am using Swift, with XCode 8. I have already defined a variable, but when I want to connect it to my button and text field, it says use of unresolved identifier. Can anyone help me?
Screenshot:
Your sum variable is defined inside the Solve function scope, so it can only be used inside that scope. You have to make your variable global (i.e. inside the UIViewController scope) for it to be visible inside all the functions.
Define var sum outside the function, under Oranges.
class ViewController : UIViewController {
#IBOutlet weak var Apples :UITextField!
#IBOutlet weak var Oranges :UITextField!
var sum : String!
#IBAction func Solve(_ sender: AnyObject)
{
var apples = Int(Apples.text!)
var oranges = Int(Oranges.text!)
sum = String(oranges! + apples!)
}
}
this is a bit odd to say but essentially here is my code below:
import UIKit
class BarcodeScanPopover: UIViewController, UIPopoverPresentationControllerDelegate {
#IBOutlet weak var navbar: UINavigationItem!
#IBOutlet weak var product: UILabel!
#IBOutlet weak var productimage: UIImageView!
#IBOutlet weak var scanner: UIView!
var scan: MTBBarcodeScanner = MTBBarcodeScanner(previewView: scanner);
override func viewDidLoad() {
So the issue I'm having is I can't declare "scan" without initiating the MTBBarcodeScanner object, but at the same time, I can't initiate the MTBBarcodeScanner object without calling "scanner" which is not possible at the top of the file. Unfortunately MTBBarcodeScanner() is not a valid init and causes crashes so that is not possible either.
I need to do this because I need to access "scan" at different points in the code - not just in one code method.
Any suggestions?
If you are sure you will always have an instance of the MTBBarcodeScanner after the view loaded, declare it as MTBBarcodeScanner!: var scan: MTBBarcodeScanner!. That makes it an implicitly unwrapped optional, which is allowed to be nil unless you try to access some property/function on it.
You should therefore then make sure that you always assign something to it before ever accessing it in any other way. That can and should be done in viewDidLoad:
scan = MTBBarcodeScanner(previewView: scanner)
You can let your MTBBarCodeScanner instance be an optional, and initially set it to nil.
var scan: MTBBarcodeScanner? = nil
Thereafter call your initializer to update its value as soon as scanner instance is available to you (e.g. in viewDidLoad).