Swift - Sum function error - ios

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.

Related

How to terminate (not segue) just one view in Swift

I am wondering how to make just 1 view terminate in iOS. I am making an app such that in the viewDidLoad() it generates 52 random strings and appends them to an array. I have it so that when you shake the device, it will perform a segue.
The problem with this is that it keeps the items in the array that I mentioned earlier. This means that when it does the user goes into that view again, it will still have the 52 random strings, plus when it goes through the viewDidLoad function, it will append 52 more strings, so if the user doesn't terminate the whole entire app, but just segues out of the view and goes back in, there will be 104 strings and not 52.
I don't want the above to happen in my app, so I am wondering how you could just terminate this one view while also performing a segue so that this problem won't happen.
Here is some code from my app:
These are the arrays I had:
var theCardsTopPlayerHas = [""]
var theCardsBottomPlayerHas = [""]
var theCardsThatWork = ["2_of_clubs", "2_of_diamonds", "2_of_hearts", "2_of_spades", "3_of_clubs", "3_of_diamonds", "3_of_hearts", "3_of_spades", "4_of_clubs", "4_of_diamonds", "4_of_hearts", "4_of_spades", "5_of_clubs", "5_of_diamonds", "5_of_hearts", "5_of_spades", "6_of_clubs", "6_of_diamonds", "6_of_hearts", "6_of_spades", "7_of_clubs", "7_of_diamonds", "7_of_hearts", "7_of_spades", "8_of_clubs", "8_of_diamonds", "8_of_hearts", "8_of_spades", "9_of_clubs", "9_of_diamonds", "9_of_hearts", "9_of_spades", "10_of_clubs", "10_of_diamonds", "10_of_hearts", "10_of_spades", "jack_of_clubs2", "jack_of_diamonds2", "jack_of_hearts2", "jack_of_spades2", "queen_of_clubs2", "queen_of_diamonds2", "queen_of_hearts2", "queen_of_spades2", "king_of_clubs2", "king_of_diamonds2", "king_of_hearts2", "king_of_spades2","ace_of_clubs", "ace_of_diamonds", "ace_of_hearts", "ace_of_spades"]
Here is what the viewDidLoad method has:
struct shuffledVar {
static var shuffled = [String]();
}
override func viewDidLoad() {
super.viewDidLoad()
upperLabelNumber.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
//MARK: - Shuffling Cards
for _ in 1...52 {
let shuffledCardList = Int(arc4random_uniform(UInt32(theCardsThatWork.count)))
let the_card = theCardsThatWork[shuffledCardList]
print("\(the_card)")
shuffledVar.shuffled.append(the_card)
theCardsThatWork.remove(at: shuffledCardList)
print("Finished Card")
}
theCardsTopPlayerHas = Array(shuffledVar.shuffled[0...25])
theCardsBottomPlayerHas = Array(shuffledVar.shuffled[26...51])
print("")
print(shuffledVar.shuffled)
print("")
print(theCardsTopPlayerHas)
print("")
print(theCardsBottomPlayerHas)
}
This is the code that segues the view:
override func motionBegan(_ motion: UIEventSubtype, with event: UIEvent?) {
performSegue(withIdentifier: "friendToDashboard", sender: self)
}
Thank you!
The problem is that you are using a static var to store your array of strings.
To solve this problem there are several solutions depending on what you need. Here there are a couple of solutions:
Solution 1
If you really need to keep the shuffled array as a Singleto, then you can empty the shuffled array in the viewDidLoad method:
override func viewDidLoad() {
super.viewDidLoad()
shuffledVar.shuffled = []
upperLabelNumber.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
...
}
Solution 2
If you do not need to keep the shuffled array as a Singleton, then you can modify it as follows:
struct shuffledVar {
var shuffled = [String]();
}
var shuffled = shuffledVar()
override func viewDidLoad() {
super.viewDidLoad()
upperLabelNumber.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
//MARK: - Shuffling Cards
for _ in 1...52 {
let shuffledCardList = Int(arc4random_uniform(UInt32(theCardsThatWork.count)))
let the_card = theCardsThatWork[shuffledCardList]
print("\(the_card)")
shuffled.shuffled.append(the_card)
theCardsThatWork.remove(at: shuffledCardList)
print("Finished Card")
}
theCardsTopPlayerHas = Array(shuffled.shuffled[0...25])
theCardsBottomPlayerHas = Array(shuffled.shuffled[26...51])
print("")
print(shuffled.shuffled)
print("")
print(theCardsTopPlayerHas)
print("")
print(theCardsBottomPlayerHas)
}
You are using static var shuffled so you are using static variable. Do you really need a static variable? If not instead of:
struct shuffledVar {
static var shuffled = [String]();
}
use:
var shuffled:[String] = []
and then in code use:
shuffled.append(the_card)
But if you need this variable to be static (for example you are using it in some other view controller) just remove all elements before adding a new one:
//MARK: - Shuffling Cards
shuffledVar.shuffled.removeAll()
You can read more about static vars https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html and more about arrays: https://developer.apple.com/documentation/swift/array

I'm passing data from UITableViewController to UIViewController through protocols and instead of int value I'm getting nil. Why?

I have two UITableViewController, the first one:
protocol FetchUserProfileData {
func getNumberOfRequests()
}
class ListEvents: UITableViewController{
var fetchInfo:FetchUserProfileData?
func getNumberOfRequests() -> Int{
return 12
}
and the UIViewController:
class UserProfileDetails:UIViewController, FetchUserProfileData {
var listEvents: UserListEvents?
func getNumberOfRequests(){
}
override func viewDidLoad(){
listEvents?.fetchInfo = self
print(listEvents?.getNumberOfRequests())
and this line: print(listEvents?.getNumberOfRequests()) gives me a nil value instead of 12... What's wrong here?
---- edit
Ok, now I see that listEvents is empty... So my question is how can I pass that data from ListEvents to UserProfileDetails?
In this code, listEvents is probably nil.
But, the way you use the protocol looks odd to me. I would expect:
getNumberOfRequests in the protocol to return Int
ListEvents should be implementing the protocol, not UserProfileDetails
The empty getNumberOfRequests() in UserProfileDetails should be deleted
You did not set listEvents. When you are using story boards then you should set the fetchInfo not earlier than in (overwriting) prepareForSegue. Google for examples, the web is full of them. When you segue programmatically then you can set the property not before you actually instanticated the new view controller. You are better of using listEvents!.fetchInfo = self because in that case you'll get an exception when listEvents is nil.
I made some change your code and this will pass data from ListEvents to UserProfileDetails.
protocol FetchUserProfileDelegate {
func getNumberOfRequests()->Int
}
class ListEvents: UITableViewController,FetchUserProfileDelegate{
var userProfile: UserProfileDetails?
override func viewDidLoad() {
userProfile = UserProfileDetails()
userProfile?.delegate = self
}
// MARK: FetchUserProfileDelegate
func getNumberOfRequests() -> Int{
return 12 // return as your target Int
}
}
class UserProfileDetails:UIViewController {
var delegate:FetchUserProfileDelegate?
override func viewDidLoad() {
if let _ = delegate{
let resultInt = delegate?.getNumberOfRequests() // get the Int form ListEvents
print(resultInt)
}
}
}
The idea of moving data from one controller to another is very common. Most of the time this is done using a segue. A controller can have a function called prepareForSegue. This function gets called before the transition happens. Inside the prepareForSegue function, the system gives you destination controller object. You take that object and set your data in it. When the transition happens, and your destination controller comes up, it already has the data you want to give to it.
Use Xcode and make a new project. Choose "Master-Detail Application". This will generate the code for you and it is a good example of how to pass data between controllers.

Count point when a specific button taped parse

Count point in a specific moment when button taped in a new column Parse for example :
#IBAction func nbTapped(sender: AnyObject) {
let PFUser.currentUser()!.objectForKey("buttonpressed") as? Int (buttonpressed)! + 1
}
Should be written as follows:
#IBAction func nbTapped(sender: AnyObject) {
var count = PFUser.currentUser()!.objectForKey("buttonpressed")
PFUser.currentUser()!["buttonpressed"] = count + 1
}
I'm not exactly Swift literate (Obj-C user), but that should work with minimal changes.

Getting types from instance of a class in Swift

I have two files which I am working on for my SpriteKit game: SPSwipes.swift and GameScene.swift.
In my SPSwipes.swift file, inside an SPSwipes class, a variable is triggered by an IBAction.
class SPSwipes: UIViewController {
#IBAction func fiveSwipes(sender: AnyObject) {
var no_of_swipes = 5
}
}
In my GameScene.swift file, an if statement checks what value has been assigned to my variable, and creates an array thereof:
if no_of_swipes == 5 {
var array = Array<UInt32>(count: 5, repeatedValue: 0)
for i in 0 ..< 5 {
array[i] = arc4random_uniform(100)
}
}
I receive this error message:
To 'fix' the problem, I realised that I needed to create an instance of my SPSwipes class, so I added this to my GameScene.swift file:
var swipes = SPSwipes()
And then I changed the if statement to say:
if swipes.no_of_swipes == 5{
...
}
Then I received this error:
As far as I'm aware, I have created an instance of the class correctly, but there is evidently an issue.
Your error is here:
#IBAction func fiveSwipes(sender: AnyObject) {
var no_of_swipes = 5
}
You have created a variable inside the function, therefore the variable doesn't exist outside of the function.
What you want is to have the variable live for as long as an object of the class lives, therefore you need to create the variable one level higher:
class SPSwipes: UIViewController {
var numberOfSwipes = 0
#IBAction func fiveSwipes(sender: AnyObject) {
numberOfSwipes = 5
}
}

How to call a function from a different function?

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.

Resources