Updating Random Integers (swift, spritekit) - ios

I have a random integer that needs to update every second, but my issue is that the random int cannot be defined outside of a function because it is an random int with the range of 0 to the screen size
var randomX = UInt32(self.size.width)
I cannot use self.size.width outside of a function. At first I thought maybe its not updating because its 1. Declared in the function didMoveToView() and 2. I declared it using "let" instead of "var". If I declare it in my function that updates every second, the variable cannot be used outside of that function which is a huge problem.

You can declare your var as an instance variable of your class (outside a method), update it in a method, and use it anywhere else in an instance of that class.
class RTest {
var randomX: UInt32
init() {
self.randomX = 2;
}
func rx5()->UInt32 {
return self.randomX * 5
}
}

Create a global class variable so you could access it anywhere in the class
class MyClass: UIViewController {
var screenWidth: CGFloat = 0.0; //Global variable for this class
func getRand() -> UInt32 {
//generate your random number
return UInt32(self.screenWidth)
}
func useRandom() {
//call getRand anytime you want to generatea a new random num
var myRandNum = getRand()
}
func override viewWillAppear(animated: Bool) {
self.screenWidth = self.view.frame.size.width
}
}
Code not tested but should give you an idea on how to go about it.
hope that helps.

Related

Having trouble plotting the x vs. y graph on Stanford CS193P Assignment 3 (2016)

I am a beginner in iOS development. I have done everything on Assignment 3 (Graphing Calculator) of the 2016 Stanford CS193P iOS development course on iTunes U (gestures, view controllers, views, segues etc.) apart from actually plotting the x vs. y graph. I am quite confused about where and how to put my code to do this; and where the drawRect is going to get the y value from. I have searched the Internet for a solution for ages. I'm assuming the model to the graph view controller is the CalculatorBrain or maybe the program of the brain but I'm not quite sure as to how the view is going to talk to this controller from the drawRect function to get the y value for a point x. If you could put me on the right track that would be very helpful. I'll paste my graph view controller and graph view code below. Thanks in advance.
//GraphViewController
import UIKit
class GraphViewController: UIViewController {
private var brain = CalculatorBrain()
var program: [AnyObject]?
#IBOutlet weak var graphView: GraphingView! {
didSet {
graphView.addGestureRecognizer(UIPinchGestureRecognizer(target: graphView, action: #selector (GraphingView.changeScale(_:))))
graphView.addGestureRecognizer(UIPanGestureRecognizer(target: graphView, action: #selector(GraphingView.panView(_:))))
graphView.addGestureRecognizer(UITapGestureRecognizer(target: graphView, action: #selector(GraphingView.doubleTapOrigin(_:))))
}
}
}
//GraphingView
import UIKit
#IBDesignable
class GraphingView: UIView {
#IBInspectable var scale: CGFloat = 50 { didSet { setNeedsDisplay() } }
#IBInspectable var linewidth: CGFloat = 2 { didSet { setNeedsDisplay() } }
var origin: CGPoint! { didSet { setNeedsDisplay() } }
/* Gesture Code
func changeScale (recognizer: UIPinchGestureRecognizer) {
switch recognizer.state {
case .Changed,.Ended:
scale *= recognizer.scale
recognizer.scale = 1.0
default:
break
}
}
func panView (recognizer: UIPanGestureRecognizer) {
switch recognizer.state {
case .Changed,.Ended:
origin.x += recognizer.translationInView(self).x
origin.y += recognizer.translationInView(self).y
recognizer.setTranslation(CGPoint(x:0,y:0), inView: self)
default:
break
}
}
func doubleTapOrigin (recognizer: UITapGestureRecognizer) {
recognizer.numberOfTapsRequired = 2
switch recognizer.state {
case .Ended :
origin = CGPoint(x: recognizer.locationInView(self).x, y:recognizer.locationInView(self).y)
default: break
}
}
*/
var axesDrawer = AxesDrawer()
override func drawRect(rect: CGRect) {
if origin == nil {
origin = CGPoint(x: bounds.midX, y: bounds.midY)
}
axesDrawer.drawAxesInRect(rect, origin: origin, pointsPerUnit: scale)
var pixelX = 0
while pixelX <= bounds.maxX {
//do some code to get value of y for current x from the brain in the view controller and plot it with UIBezierPath
pixelX += 1/contentScaleFactor
}
}
}
Updated Answer - Using a Function Pointer
The previous answer is one way to do it using a data source. It is modeled after the way a UITableViewController gets its data.
Reading though the assignment, it seems the Prof wants you to use an optional function pointer instead.
Do the following:
Create an optional variable in the GraphingView to hold a function pointer:
var computeYForX: ((Double) -> Double)?
Apply didSet to that variable and have it call self.setNeedsDisplay() when it is set. This will tell iOS that drawRect needs to be called.
In your calculator when it is time to draw, set the computeYForX property of the GraphingView to a (Double) -> Double function in your GraphViewController. If you want to remove the function (for instance, when someone resets the calculator), set the property to nil.
In drawRect, check to make sure computeYForX is not nil before using it to graph the function. Use guard or if let to safely unwrap the function before using it.
Previous Answer - Using a DataSource
You need to add a Data Source to your GraphingView. First define a protocol called GraphDataSource:
protocol GraphDataSource: class {
func computeYforX(x: Double) -> Double
}
Add a dataSource property to the GraphingView:
class GraphingView: UIView {
weak var dataSource: GraphDataSource?
Have your GraphViewController implement that protocol by adding GraphDataSource to the class definition line, by implementing computeYForX(), and by setting itself as the dataSource in didSet for graphView:
class GraphViewController: UIViewController, GraphDataSource {
private var brain = CalculatorBrain()
var program: [AnyObject]?
#IBOutlet weak var graphView: GraphingView! {
didSet {
graphView.dataSource = self
graphView.addGestureRecognizer(UIPinchGestureRecognizer(target: graphView, action: #selector (GraphingView.changeScale(_:))))
graphView.addGestureRecognizer(UIPanGestureRecognizer(target: graphView, action: #selector(GraphingView.panView(_:))))
graphView.addGestureRecognizer(UITapGestureRecognizer(target: graphView, action: #selector(GraphingView.doubleTapOrigin(_:))))
}
}
func computeYForX(x: Double) -> Double {
// call the brain to calculate y and return it
}
}
Then in drawRect, call computeYForX() on the dataSource when you need a y value:
let y = dataSource?.computeYForX(x)
I used existing functionality in calculator brain. Specifically, inside brain, I created a public method that made a calculation based on a program, stored as any object through the property list typecast (we did that in the save/restore part). All the commands were there - I just packaged it in a method. I use this method for a lot of stuff - so I never rewrite code to evaluate a sequence of operands.
In the public interface, that is just a function that is accessible from any instance of brain. In particular, in preparing for segue to the graph view, I pointed the graph view controller to this function. I also passed the program existing in the brain at that moment, so that any expression valid in the calculator can be plotted. The latter was a goal for me because it makes sense. I wanted to avoid rewriting the function that interprets the operands.
The graph view requires a function (can be brain or any other specification) and a "program" that is required in order to plot expressions. So it is a general class requiring a specific form for describing the operations. I take that as a perfectly "legal" solution.
Drawrect then used the function and the program to draw the curves.

Swift. Use of 'self' in method call before all stored properties are initialized [duplicate]

This question already has answers here:
Calling instance method during initialization in Swift
(8 answers)
Closed 6 years ago.
I have a class
class ChartView: UIView
{
class: DotView {
let circleView1: UIView
let circleView2: UIView
init (view: UIView)
{
self.view = view
self.circleView1 = self.buildCircle(some rect here)
self.circleView2 = self.buildCircle(some rect here)
func buildCircle(rect: CGRect) -> UIView
{
let dotView = UIView(frame: rect)
dotView.backgroundColor = UIColor.whiteColor()
dotView.layer.cornerRadius = dotView.bounds.width / 2
self.view.addSubview(dotView)
return dotView
}
}
}
But I got this error:
Use of 'self' in method call 'buildCircle' before all stored properties are initialized
So I just want to create objects in some method and then assign it to the stored properties. How can I fix my code?
You can't call methods on self before all non-optional instance variables are initialized.
There are several ways to go around that.
Change properties to optionals or implicitly unwrapped optionals
(not recommended)
Make the buildCircle() method static or just a
function in the file and call the addSubview() for all the circles
after all of the properties were initialized and you called
super.init()
etc. You just have to avoid calls to self before the
class was initialized.
For solving of this issue it is possible to use these approaches:
class MyClass: NSObject {
var prop: String = ""
override init() {
super.init()
self.setupMyProperty()
}
func setupMyProperty() {
prop = "testValue"
}
}
class MyClass1: NSObject {
var prop: String = ""
override init() {
prop = MyClass1.setupMyProperty()
super.init()
}
class func setupMyProperty() -> String{
return "testValue"
}
}
You can create your circleView in the function willMoveToSuperview.
In this lifecycle function you are sure to have ChartView allocated properly, so:
override func willMoveToSuperview(newSuperview: UIView?) {
self.circleView1 = self.buildCircle(some rect here)
self.circleView2 = self.buildCircle(some rect here)
}

Button in Xcode doesn't change a variable - Swift

I am trying to change the value of a variable in Xcode 7 with Swift. For some strange reason, it just doesn't work.
Here are the functions I used.
#IBAction func ten(sender: AnyObject) {
var percentage = 0.10
print("test")
}
#IBAction func twentyBtn(sender: AnyObject) {
var percentage = 0.20
}
#IBAction func fifteenBtn(sender: AnyObject) {
var percentage = 0.15
}
#IBAction func twentyfiveBtn(sender: AnyObject) {
var percentage = 0.25
}
#IBAction func thirtyBtn(sender: AnyObject) {
var percentage = 0.30
}
Then later in the code I use the percentage variable in this function.
#IBAction func calcTip(sender: AnyObject) {
var billAmount: Int? {
return Int(billField.text!)
}
var tipTotal = percentage * Double((billAmount)!)
toalLabel.text = String(tipTotal)
testLabel.text = String(percentage)
}
I don't understand why this shouldn't work because I also have this variable underneath my outlets where at the beggining of the code.
What's even more confusing is that if I try to see if it the button would print into the output, as you see I've tried for the one of the buttons, IT WORKS. Even trying to change the text within a label works, but for some strange reason it won't change a variable.
I'm not sure if this could be a bug with Xcode either.
Declare and initialize your percentage variable outside of your IBAction functions.
Like Mukesh already explained in the comments, if you are writing var percentage = 0.10 within one of these functions, you are not assigning 0.10 to the correct variable. Instead, you are creating a new variable within the scope of that function.
Any code written outside of that function cannot access it, and unless you are returning this value or passing it to a different function, the variable will be deleted by the garbage collector after the program finishes executing that function (so pretty much immediately).
Long story short, your code should look something like this instead:
var percentage = 0;
#IBAction func ten(sender: AnyObject) {
percentage = 0.10
print("test")
}
#IBAction func calcTip(sender: AnyObject) {
var billAmount: Int? {
return Int(billField.text!)
}
var tipTotal = percentage * Double((billAmount)!)
toalLabel.text = String(tipTotal)
testLabel.text = String(percentage)
}

Incrementing Array Element By One In Swift

I am Currently working on a swift project in XCode, and I've encountered an issue where I cannot increment an array's one element by through various endeavours.
My ViewController.Swift
import UIKit
class FailureViewController: UIViewController {
#IBOutlet weak var failFactLabel: UILabel!
let failFact = Failure()
override func viewDidLoad() {
super.viewDidLoad()
failFactLabel.text = failFact.failArray[0]
}
#IBAction func showFunFact() {
//this is where the issue is
}
}
For the function showFunFact I have previously tried
for var x = 0; x < failArray.cout; x++ {
failFactLabel.text = failFact.failArray[x]
}
but encountered the error: "Use of Unresolved Identifier".
Putting this aside, I decided to use
for var x = 0; x < 10; {
x+=1
}
Although this does not generate an error however, I see it stops at the first element in my array. I tried +=5 and it displays the 5th element in my array once, I believe this code runs through once. I need it to be a consistently working piece so it continuously displays the next element, I am stumped because this should theoretically work since it is called a "Loop" Any help or suggestion is Appreciated!
Objective Redefined:
I am trying to show one fact at a time, before this I have used a random function to generate a random fact every time however things tend to get repetitive and therefore I decided to start on the initial array index is 0 and grab the next fact (next element in array) every time the button is pressed (Thanks to Luk's Question)
You need to create an instance variable to hold the current factIndex, if that is what you actually are trying:
import UIKit
class FailureViewController: UIViewController {
#IBOutlet weak var failFactLabel: UILabel!
var factIndex = 0
let failFact = Failure()
override func viewDidLoad() {
super.viewDidLoad()
failFactLabel.text = failFact.failArray[factIndex]
}
#IBAction func showFunFact() {
factIndex++
if factIndex >= failFact.failArray.count then {
factIndex = 0
}
failFactLabel.text = failFact.failArray[factIndex]
}
}

Swift: Invoking subclass function in base class version of init

In Swift, how can you invoke a subclass's function in the base class's init method? Essentially, the goal is to ensure each subclass invokes its own version of initGrid, and then all the code to set numRows and numCols is defined only once, in the base class.
However, when initializing a subclass, the initGrid function from the base class -- not the subclass -- is run instead. This results in an array index exception since grid is empty unless the subclass creates it.
class BaseGrid {
var grid = [[NodeType]]()
var numRows = 0
var numCols = 0
init() {
// Init grid
initGrid()
// Set <numRows>
numRows = grid.count
// Set <numCols>
numCols = grid[0].count
// Verify each row contains same number of columns
for row in 0..<numRows {
assert(grid[row].count == numCols)
}
}
// Subclasses override this function
func initGrid() {}
}
class ChildGrid: BaseGrid {
override init() {
super.init()
}
override func initGrid() {
grid = [
[NodeType.Blue, NodeType.Blue, NodeType.Blue],
[NodeType.Red, NodeType.Red, NodeType.Red],
[NodeType.Empty, NodeType.Blue, NodeType.Empty]
]
}
}
if you will subclass and override initGrid, it will call method in current scope.
In base class, you can stay it empty, as abstract.
I.e.:
class AdvancedGrid: BaseGrid {
override init() {
super.init()
}
override func initGrid() {
// here is you custom alghoritm
}
}

Resources