Swift - Newbie question. Passing variable values between different files, functions and views - ios

newbie swift programmer here that needs help with something that probably is trivial...
This is in different File, different View:
class CanvasContainerView: UIView {
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// here are all of the calculations that lead to scoreString being calculated..
var scoreString = round(1000 * accuracyTotal / angleTotal)
}
//lots of other code
}
I need the value of my calculated "scoreString" to be accessible in a different file, different controller. How can i pass this value through if i'm using TouchesMoved function ? Below is how i tried to implement it in different file but failed miserably as there is no "scoreString" in scope:
import UIKit
class CanvasMainViewController: UIViewController {
#IBOutlet weak var ScoreText: UITextField!
/// Prepare the drawing canvas.
/// - Tag: CanvasMainViewController-viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
ScoreText.text = "\(CanvasContainerView.touchesMoved(scoreString))"
}
//lots of code
}
In the end i want my score to be displayed on top of the screen:
So i am aware that there are questions like this already on Stack but whats specific about my question is that im using this "touchesMoved" overriden function that doesn't let me return any value. It shouts it needs void return type.
I will be very thankful for any help.

Using a delegate is the good method :
// the protocol (ie the method called by container view in the controller)
protocol CanvasContainerViewDelegate {
func scoreUpdate(fromView view:CanvasContainerView, newScore: Double)
}
class CanvasContainerView: UIView {
// the delegate that will be called
var delegate: CanvasContainerViewDelegate?
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// here are all of the calculations that lead to scoreString being calculated..
var scoreString = round(1000 * accuracyTotal / angleTotal)
// Telling the delegate the new score value
delegate?.scoreUpdate(fromView: self, newScore: scoreString)
}
//lots of other code
}
class CanvasMainViewController: UIViewController, CanvasContainerViewDelegate {
#IBOutlet weak var ScoreText: UITextField!
#IBOutlet weak var containerView: CanvasContainerView!
/// Prepare the drawing canvas.
/// - Tag: CanvasMainViewController-viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
// set the controller as a delegate of the view
containerView.delegate = self
}
// Update the score (called by the view)
func scoreUpdate(fromView view: CanvasContainerView, newScore: Double) {
ScoreText.text = "\(newScore)"
}
//lots of code
}

Apparently adding public in front of the var declared on top of the file solved the problem. Thank you for participation in trying to help me.

Related

Protocol/Delegate function doesn't trigger (Swift) [duplicate]

I have an IBOutlet-connected UIView object (innerView) sitting over view controller (UIViewController)'s view. I want to let the user rotate innerView with their finger. So I have a subclass (TouchView) of UIView set to innerView's class. As the user rotates the view object, I want the view controller to receive a value from TouchView. And what I have is the following.
// UIView
protocol TouchDelegate: class {
func degreeChanged(degree: Double)
}
class TouchView: UIView {
weak var delegate: TouchDelegate? = nil
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let aTouch: AnyObject = touches.first! as UITouch
let newLoc = aTouch.location(in: self.superview)
...
...
let degree = { (radians: Double) -> Double in
return radians * 180 / M_PI
}
self.delegate?.degreeChanged(degree: degree)
}
}
// UIViewController
class ViewController: UIViewController, TouchDelegate {
#IBOutlet weak var innerView: UIView!
// MARK: - View
override func viewDidLoad() {
super.viewDidLoad()
let touchView = TouchView()
touchView.delegate = self
}
// MARK: - From TouchView
func degreeChanged(degree: Double) {
print(degree) // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< no call
}
}
Well, the view controller never receives a delegate call from TouchView. What am I doing wrong? Thank you for your help.
I see 2 problems
You created a new instance of touchView and did not add it into your view controller's views
Your innerView is not an instance of touchView and its delegate is not set
My approach to your situation would look something like this:
// UIViewController
class ViewController: UIViewController, TouchDelegate {
#IBOutlet weak var innerView: TouchView!
// MARK: - View
override func viewDidLoad() {
super.viewDidLoad()
innerView.delegate = self
}
// MARK: - From TouchView
func degreeChanged(degree: Double) {
print(degree) // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< no call
}
}

Why does my program not work properly when trying to directly set my variable to a random integer using Int.random()?

I am following an online tutorial and when trying to directly set my randomBallNumber variable to a random number between 1 and 4 using randomBallNumber = Int.random(in: 0...4), my code doesn't work. However, when I first use var randomBallNumber = 0 and then change its value to a random one inside of a function, it runs properly.
Works:
class ViewController: UIViewController {
let ballArray = ["ball1", "ball2", "ball3", "ball4", "ball5"]
var randomBallNumber = 0
func newBallImage() {
ImageView.image = UIImage(named: ballArray[randomBallNumber])
randomBallNumber = Int.random(in: 0...4)
}
#IBOutlet weak var ImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
newBallImage()
}
#IBAction func askButtonPressed(_ sender: Any) {
newBallImage()
}
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
newBallImage()
}
}
Doesn't work:
class ViewController: UIViewController {
let ballArray = ["ball1", "ball2", "ball3", "ball4", "ball5"]
var randomBallNumber = Int.random(in: 0...4)
func newBallImage() {
ImageView.image = UIImage(named: ballArray[randomBallNumber])
}
#IBOutlet weak var ImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
newBallImage()
}
#IBAction func askButtonPressed(_ sender: Any) {
newBallImage()
}
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
newBallImage()
}
}
The only console error I am getting is:
2019-07-10 07:22:45.328092+0300 8BallPool[86631:3716368] libMobileGestalt MobileGestalt.c:890: MGIsDeviceOneOfType is not supported on this platform.
and it shows for both variants.
The expected result would be for the image to change when the Ask! button is pressed which it doesn't when using the second piece of code.
var randomBallNumber = Int.random(in: 0...4)
This will be initialized once, and after that the value of randomBallNumber will not change unless you change it again.
So instead of making it as a global variable better make a function like:
func getRandomNumber() -> Int {
return Int.random(in: 0...4)
}
And call it wherever you need the randomBallNumber, like:
ImageView.image = UIImage(named: ballArray[getRandomNumber()])
Note: Always declare variable and outlet names in camelCase, where the first character should be small. Here your ImageView is a very wrong name, instead name it something like randomBallImageView.

Swift / Xcode - How to clear a label when touching inside a textfield?

I am creating a simple calculator app - everything works fine but I'd like to clear the result label when the user enters a new number in a textfield (or just touches inside a textfield).
Right now I am using a touchesBegan function to clear the label (which also dismisses the keyboard:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
resultLabel.text = ""
}
Problem is of course that it doesn't matter where the user touches on the screen (for example accidentally doesn't hit the calc button), the label will always be cleared.
Is there a way to clear the "resultLabel" when the user touches the "numberField" textfield?
Thanks!
#IBOutlet weak var resultLabel: UILabel!
#IBOutlet weak var numberField: UITextField!
override func viewDidLoad(){
super.viewDidLoad()
numberField.delegate = self
}
extension viewcontroller: UITextFieldDelegate {
func textFieldDidBeginEditing(textField: UITextField) {
resultLabel.text = ""
}
}
For clear resultlable first thing you need to give delegate to your text filed
numberField.delegate = self
Setup your viewcontroller to implement UITextFieldDelegate
Add below method to your viewcontroller
class viewcontroller: UIViewController,UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
resultLabel.text = ""
}
}
You can use text field Delegate methods on your textField where the user is entering the numbers.
textField.delegate = self
textField.tag = 0
Add a tag to your textField and check it in didBeginEditing.
func textFieldDidBeginEditing(textField: UITextField) {
if textField.tag == 0 //Or whatever tag you attach{
//Do the required task
}
}

keyboard controlling function error with Xcode 7

I was trying to create a function in order to put keyboard away by clicking outside of the keyboard or return key within the keyboard, but unfortunately it only worked when I clicked outside of the keyboard, it doesn't work to press the return key in the keyboard.
import UIKit
class ViewController: UIViewController,UITextFieldDelegate {
#IBOutlet var numberEnter: UITextField!
#IBAction func findButton(sender: AnyObject) {
resultLabel.text = numberEnter.text
}
#IBOutlet var resultLabel: UILabel!
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.
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField:UITextField) -> Bool{
textField.resignFirstResponder()
return true
}
}
If you haven't set the delegate for your text field you will need to do that. You can set the delegate in Interface Builder or in code. See this StackOverflow answer for an example: Text Field Should Return, is this correct for ios7?

Instance var in event handler is always initial value

I have a problem with accessing an instance var in an event handler.
When I'm trying to access an instance var in an event handler, it seems to always have the initial value, even though the value has changed since.
In my simple demo app, I have a horizontal slider and a UIImageView:
ViewController.swift:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var slider: UISlider!
var canvas:MyCanvas?
override func viewDidLoad() {
super.viewDidLoad()
self.canvas = MyCanvas()
}
#IBAction func sliderValueChanged(sender: UISlider) {
self.canvas!.sliderValueUpdated(sender.value);
}
}
MyCanvas.swift:
import Foundation
import UIKit
class MyCanvas : UIImageView {
// the var I care about
var sliderValue:Float = 0.5;
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override init() {
super.init()
}
func sliderValueUpdated (newValue:Float) {
self.sliderValue = newValue;
// prints the correct value
println(self.sliderValue)
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
// always prints initial value, 0.5
println(self.sliderValue)
}
}
I set MyCanvas.swift as custom class for the UIImageView.
So when I adjust the slider, it prints out the correct value for self.sliderValue. However, when I'm firing a touch event after that, it always prints out the initial value, 0.5 instead of the slider value.
Why is that?
How do I fix this?
I think your problem is that you don't have an IBOutlet to your canvas. By initializing the canvas in viewDidLoad, the initialized canvas is not actually on the screen (you would have to add it to the subviews). Thus, your sliderValueChanged IBAction is not actually updating the sliderValue property of the MyCanvas on the screen. I recommend setting your UIImageView in the storyboard as a MyCanvas class and making an IBOutlet to that MyCanvas object in your Storyboard. Then remove the canvas = MyCanvas() from your viewDidLoad function.

Resources