How to call a function from a different function? - ios

I'm trying to make a simple app that counts the characters of a textfield, but when the user inputs the text, the function that converts the user-inputed string into a var and the function that counts the characters are executed at once. Here's the code:
import UIKit
class ViewController: UIViewController {
#IBOutlet var myTextField : UITextField
#IBOutlet var userTextField : UITextField
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myTextField.text = fullConstant
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func modifyMyVariable(sender : AnyObject) {
myVariable = userTextField.text
}
#IBAction func clickMe(sender : AnyObject) {
countCharacters(&fullConstant)
println(fullConstant)
myTextField.text = fullConstant
}
}
And here's the "OtherFile.swift" where the functions are located:
import Foundation
var fullConstant = "Type something!"
var myVariable = ""
func modifyMyVariable() {
println()
}
func countCharacters(inout fullConstant: String) {
let FirstPart = "There are "
let LastPart = " characters"
var numberOfCharacters = countElements(myVariable)
switch numberOfCharacters {
case 0 :
fullConstant = "There isn't any character yet"
case 1 :
fullConstant = "There is just one character"
default :
fullConstant = FirstPart + String(numberOfCharacters) + LastPart
}
}
Both functions execute as soon the userTextField is edited, but if the user inputs one character, the countCharacters function takes the var myVariable before it's modified by the function modifyMyvariable, so it doesn't count the last character added.
To solve this, I've thought that I could call the function countCharacters from the function modifyMyVariable, so the variable myVariable has already changed when it counts the characters.

Change the following and see if it's then easier to fix your problem.
You should always only link each event to one IBAction. Your IBActions shouldn't be named after what you're trying to do in them; they should be named after the event that triggers them. For example, "modifyMyVariable" should be called "textEdited" or similar.
In that "textEdited" method, do all the work you need to do. If you need to call another function, call it from there instead of linking to two IBActions.
Put code in your "OtherFile" inside a
class OtherFile {
}
block, and hold an instance to that class as a variable in your view controller. You want to avoid declaring global functions outside of classes.
Not related, but name your constants using camelCase with first letter lower case, just like your variables. So FirstPart should be firstPart.
Avoid using 'inout' as much as possible. Each language has it's conventions; in ObjC and Swift, pass in values needed to do work, and return values that result from that work. So:
func countCharacters(text: String) -> (String)
Putting it all together, your 'modifyMyVariable' function (which should really be called 'textEdited') will look something like this:
myVariable = userTextField.text
let characterCount = self.myOtherFileInstance.countCharacters(myVariable)
myTextField.text = characterCount
and the other function (clickMe) should be deleted.

Related

Swift - Sum function error

I'm trying to make some view controllers that save a variable of a label every time and sum it to a total var. At the last view controller, show the result.
My code is:
FirstViewController
#IBAction func playSystemSoundV1(sender: UIButton) {
// Other code...
puntsLocal = 3
}
#IBAction func playSystemSoundRet(sender: UIButton) {
// Other code...
puntsLocal = 5
}
This code is similar for 5 controller. At the end of the controller I have a button to pass from one viewController to another. When I click I do the code above:
#IBAction func puntuacioAction(sender: UIButton) {
let puntuacion = Sum()
puntuacion.sumPoints(puntsLocal)
}
Sum Class
import Foundation
class Sum {
var points = 0
// Method to sum points from every question.
func sumPoints(num: Int) {
self.points += num
}
func getPoints() -> Int {
return points
}
}
The problem is that returns only the last number without do any kind of sum. What can I do? In other languages it's very easy to resolve but in Swift I cannot reach the answer. Help please!
Thanks.
You need to declare your variable outside the function:
let puntuacion = Sum()
#IBAction func puntuacioAction(sender: UIButton) {
puntuacion.sumPoints(puntsLocal)
}
Your original code created a new Sum everytime the function was called, explaining the behavior you are seeing. In Swift, variable declarations are bound to the scope they appear (e.g., inside a function, inside a class, etc).
If, besides that, you want to share this Sum object across many view controllers, this might help:
class Sum {
static let shared = Sum()
...
}
and use it like this:
#IBAction func puntuacioAction(sender: UIButton) {
Sum.shared.sumPoints(puntsLocal)
}
Of course, you should then delete the let puntuacion = Sum() line.

Getting input from text field in ViewController and using in another class

In ViewController.swift, I have a text field whose input I would like to use and manipulate in my other class, Conjugate.swift. I am capturing the input at the same time the keyboard is hidden, like so:
import UIKit
class MainViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var mainTextField: UITextField!
var input: String!
override func viewDidLoad() {
super.viewDidLoad()
mainTextField.delegate = self
}
/* KEYBOARD HIDE */
func textFieldShouldReturn(textField: UITextField) -> Bool {
input = self.mainTextField.text
textField.resignFirstResponder()
return true;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
And then in my other class:
class Conjugate {
var infinitive: String!
var isEndingAr = false
func conjugate() {
// gets verb from text field
infinitive = MainViewController().input
// checks verb ending and sets value to booleans
if (infinitive.hasSuffix("ar")) {
isEndingAr = true
}
}
}
Here is the error I'm getting:
fatal error: unexpectedly found nil while unwrapping an Optional value
I know that input in MainViewController.swift is still nil. I just don't know why. What am I doing wrong?
When you do infinitive = MainViewController().input, MainViewController() just creates a new instance of MainViewController. That new instance never calls textFieldShouldReturn and therefore its input will be nil. Instead, add a reference from Conjugate to MainViewController.
var mainViewController: MainViewController?
Then in textFieldShouldReturn create a Conjugate and assign its property:
let conjugate = Conjugate()
conjugate.mainViewController = self
Then in the conjugate() method, instead of creating a new view controller, refer to the property:
func conjugate() {
// gets verb from text field
infinitive = self.mainViewController!.input!
// checks verb ending and sets value to booleans
if (infinitive.hasSuffix("ar")) {
isEndingAr = true
}
}
}
Also, like #emresancaktar said, input should be optional, since it might be nil. However, infinitive does not have to be optional.

Instance member Goals cannot be used on type "ViewController" SWIFT XCODE

Hey I'm trying to Categorised or basically manually list stats in a way where i can give the program conditions to find exactly what I'm looking for so like if i was looking for how many goals where scored in the first 0 to 45 (first half) of a game that Barcelona was playing in on a specific day i could. Say in code find me all the games that were played on this date and where two or more goals were score in the first 0 to 45 minutes. As I'm not sure if i did it right but i tried to give the strings a number/Int value to represent the minute the goal was score in the game. And i also did the same with the date for the game. But the problem is there's an error at (don't Mind The spelling error lol "Barcelona")
let BarcelonavsRealMadrid1 = [Goals, Penaltys]
Instance member Goals cannot be used on type "ViewController"
also if theres a better way to do this please you can rewrite my code. Thanks
Code:
import UIKit
class ViewController: UIViewController {
let Games = [BarcelonavsRealMadrid1: 1/13/14]
let SpainPrimeraDivision = [RealMadrid, Bareclonia]
let RealMadrid = [BarcelonavsRealMadrid1: 1/12/14]
let Bareclonia = [BarcelonavsRealMadrid1: 1/12/14]
let BarcelonavsRealMadrid1 = [Goals, Penaltys]
let Goals : [String : Int] = ["BarcelonaGoal":21,"RealMadridGoal":23]
let Penaltys : [String : Int] = ["RealMadridPenalty":21,"BarcelonaPenalty":23]
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.
}
}
You cannot reference one instance variable in the default assignment of another one. The following is the simplified version of your problem:
class ViewController: UIViewController {
let foo = 12
let bar = foo
}
Normally you have to setup the variables in the init method. But since you have a UIViewController here, you have to do it in viewDidLoad. You therefore have to write
class ViewController: UIViewController {
var foo : Int!
var bar : Int!
override func viewDidLoad() {
super.viewDidLoad()
foo = 12
bar = foo
}
}
Your code has a few more problems than that however:
you are trying to access variables before they are declared all over the place
what is 1/12/14 supposed to be? I guarantee you it is not a date
stop starting variable names with upper case letters
What you have to do:
rename all your variables
change all you variables to var and assign value to them in the correct order inside viewDidLoad
deal with the date situation
Your issue is that you are making references between class properties during initialization - this isn't permitted. One way around this is to set some of the things initially, then in viewDidLoad or in viewWillAppear set the dependencies, like this:
//-------All Games Ever played------------------------------------
var BarcelonavsRealMadrid1 = [[String : Int]]() // if you want this globally
let Goals : [String : Int] = ["BarcelonaGoal":21,"RealMadridGoal":23]
let Penaltys : [String : Int] = ["RealMadridPenalty":21,"BarcelonaPenalty":23]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
BarcelonavsRealMadrid1 = [Goals, Penaltys]
}
also there were few more problems suggested by #luk2302 in his answer
Try this
var BarcelonavsRealMadrid1:[[String:Int]] { return [Goals, Penaltys] }

Counting beans with ReactiveCocoa 4 and an NSButton

I have the following:
Two interesting classes: a ViewController and a ViewModel
A button nsButtonMorePlease:NSButton in the view of ViewController
A text box nsTextView:NSTextView in the view as well
I want the following behavior:
When you launch the program, the "count" starts at 0 and is displayed in the text box nsTextView
When you press the button nsButtonMorePlease, the count is incremented by 1 and the updated count is reflected in the nsTextView
I would like to ensure:
I use ReactiveCocoa 4 (that's the point kind of)
The model class contains numberOfBeans: MutableProperty<Int> starting at 0
The design is purely functional or close to it - that is (if I understand the term), every link in the chain mapping the event of mouse click to the MutableProperty of numberOfBeans to responding to it in the text view, is all without side effects.
Here's what I have. Fair warning: this doesn't come close to working or compiling I believe. But I do feel like maybe I want to use one of combineLatest, collect, reduce, etc. Just lost on what to do specifically. I do feel like this makes something easy quite hard.
class CandyViewModel {
private let racPropertyBeansCount: MutableProperty<Int> = MutableProperty<Int>(0)
lazy var racActionIncrementBeansCount: Action<AnyObject?, Int, NoError> = {
return Action { _ in SignalProducer<Int, NoError>(value: 1)
}
}()
var racCocoaIncrementBeansAction: CocoaAction
init() {
racCocoaIncrementBeansAction = CocoaAction.init(racActionIncrementBeansCount, input: "")
// ???
var sig = racPropertyBeansCount.producer.combineLatestWith(racActionIncrementBeansCount.)
}
}
class CandyView: NSViewController {
#IBOutlet private var guiButtonMoreCandy: NSButton!
#IBOutlet private var guiTextViewCandyCt: NSTextView!
}
class CandyViewModel {
let racPropertyBeansCount = MutableProperty<Int>(0)
let racActionIncrementBeansCount = Action<(), Int, NoError>{ _ in SignalProducer(value: 1) }
init() {
// reduce the value from the action to the mutableproperty
racPropertyBeansCount <~ racActionIncrementBeansCount.values.reduce(racPropertyBeansCount.value) { $0 + $1 }
}
}
class CandyView: NSViewController {
// define outlets
let viewModel = CandyViewModel()
func bindObservers() {
// bind the Action to the button
guiButtonMoreCandy.addTarget(viewModel.racActionIncrementBeansCount.unsafeCocoaAction, action: CocoaAction.selector, forControlEvents: .TouchUpInside)
// observe the producer of the mutableproperty
viewModel.racPropertyBeansCount.producer.startWithNext {
self.guiTextViewCandyCt.text = "\($0)"
}
}
}

I am getting errors such as " braced block of statements is an unused closure" and expected expression

This is my first time doing a simple project in swift and these errors are bugging me for last couple of hours. I have this code below and even though i have curly braces around and statements inside the if/else i still get that errors. Any help would be greatly appreciated guys.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var `switch`: UISwitch!
#IBOutlet var Answer: UILabel!
#IBOutlet var tempInput: UITextField!
//aqnswer value
#IBAction func switchPressed(sender: AnyObject)
{
if switch.on {
self.Answer.text = "cel to fah"
}
else {
self.Answer.text = "fah to cel"
}
}
//textfield value
#IBAction func calculate(sender: AnyObject)
{
//get user input
// value = celcius
var Value:Int = tempInput.text.toInt()!
var toFah :Int = ( 32 + Value * 9 ) / 5
//to celcius
var toCel: Int = (Value-32) * 5 / 9
if switch.on {
self.Answer.text = toFah.description
}
else {
self.Answer.text = toCel.description
}
// println(fah)
// Answer.text = fah.description
}
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.
}
}
The Swift Language Guide says:
If you need to give a constant or variable the same name as a reserved
Swift keyword, surround the keyword with back ticks (`) when using it
as a name. However, avoid using keywords as names unless you have
absolutely no choice.
In your example you have indeed a choice…
But if you really really really want to use switch as a variable name you have to wrap all occurrences of switch in back ticks.

Resources