Access a variable outside a for-loop Swift - ios

I am trying to access "numOne" right before the return statement and I can't seem to find why it is not working. Everything was fine accessing "numTwo". Is the reason because "numOne" is inside a range?
func checknumber() -> String {
var numTwo = 0
var range = 0...b
for numOne in range {
numTwo = b-numOne
if let result = isCommon(numOne: numOne, numTwo: numTwo) {
println("Success - \(numOne) and \(numTwo) Work")
break
} else {
println("Failure - \(numOne) and \(numTwo) Does NOT Work")
}
var numOneFinal = numOne
}
var numberTwo = "\(numTwo)"
var numberOne = "\(numOneFinal)"
return numberTwo
}
If anyone could point me in the right direction that would be greatly appreciated.

numOne is scoped by the for statement in which it is defined.
To gain access to the last value of numOne after the loop, add a new variable, say numOneFinal, at the same level as numTwo, then assign numOne's value to it within the for loop.

You can't access numOne outside of the for loop, because it's out of the scope. You can only access numOne within the loop

Related

How to observe a change in a class's property from another class

I've got a question on property observers. There's some example code below. What I want is for the property Analysis.hasChanged to be updated to true if a.value is changed. Is there a way I can do this?
class Number {
var value: Double
init(numberValue: Double) {
self.value = NumberValue
}
}
class Analysis {
var a: Number
var hasChanged = false
init(inputNumber: Number) {
self.a = inputNumber
}
}
testNumber = Number(numberValue: 4)
testAnalysis = Analysis(inputNumber: testNumber)
print(testAnalysis.hasChanged) // will print "false"
testNumber.value = 10
print(testAnalysis.hasChanged) // will still print "false", but I want it to print "true"
In the end, I want the user to be able to be notified if any of their analyses use numbers that have been changed so that they can update the results of the analyses if they choose.
You can use the built-in property observers provided by Swift.
Every time you set a new value, the didSet will be called. You just need to attach the closure, wrapping the desired behaviour, to the Number class
class Number {
var valueDidChangeClosure: (()->())?
var value: Double {
didSet {
//won't call the valueDidChangeClosure
//if the value was changed from 10 to 10 for example..
if oldValue != value {
valueDidChangeClosure?()
}
}
}
init(numberValue: Double) {
self.value = numberValue
}
}
class Analysis {
var a: Number
var hasChanged = false
init(inputNumber: Number) {
self.a = inputNumber
self.a.valueDidChangeClosure = {
self.hasChanged = true
}
}
}
let testNumber = Number(numberValue: 4)
let testAnalysis = Analysis(inputNumber: testNumber)
print(testAnalysis.hasChanged) // will print "false"
testNumber.value = 10
print(testAnalysis.hasChanged) // will print "true"
I would do something like this, I apologize in advance if I have some syntax wrong (I usually use C/C++, think of this as more psudo code since you'd have to have a way to copy Number classes, etc.).
class Number {
var value: Double
init(numberValue: Double) {
self.value = NumberValue
}
}
class Analysis {
var a: Number
var _a: Number
bool hasChanged() {
if (a != _a) {
_a = a
return true;
}
return false;
}
init(inputNumber: Number) {
self.a = inputNumber
self._a = self.a
}
}
testNumber = Number(numberValue: 4)
testAnalysis = Analysis(inputNumber: testNumber)
print(testAnalysis.hasChanged()) // will print "false"
testNumber.value = 10
print(testAnalysis.hasChanged()) // will still print "false", but I want it to print "true"
In the end, I want the user to be able to be notified if any of their analyses use numbers that have been changed so that they can update the results of the analyses if they choose.
I don't know if this really addresses that question, I based my answer off of the code you provided. So there may be additional functionality if you want there to be some triggering method (instead of calling .hasChanged()).
Comparing doubles (and any other floating point type) with '=' or '!=' is not a good idea.
Use epsilon function instead.
Details: jessesquires.com/blog/floating-point-swift-ulp-and-epsilon/

Swift call random function

I got 3 different functions and I want to call one of these randomly.
if Int(ball.position.y) > maxIndexY! {
let randomFunc = [self.firstFunction(), self.secondFunction(), self.thirdFunction()]
let randomResult = Int(arc4random_uniform(UInt32(randomFunc.count)))
return randomFunc[randomResult]
}
With this code I call all functions, and the order is always the same. What can I do to just call one of these?
The reason the three functions are called (and in the same order) is since you are causing them to be called when you put them in the array.
This:
let randomFunc = [self.firstFunction(), self.secondFunction(), self.thirdFunction()]
Stores the return value of each function in the array since you are invoking them (by adding the '()').
So at this point randomFunc contains the return values rather than the function closures
Instead just store the functions themselves with:
[self.firstFunction, self.secondFunction, self.thirdFunction]
Now if you want to call the selected method do not return its closure but invoke it:
//return randomFunc[randomResult] // This will return the function closure
randomFunc[randomResult]() // This will execute the selected function
if Int(ball.position.y) > maxIndexY! {
let randomNumber = Int.random(in: 0...2)
if randomNumber == 0 {
firstFunction()
} else if randomNumber == 1 {
secondFunction()
} else if randomNumber == 2 {
thirdFunction()
}
}
I expect it should work
if Int(ball.position.y) > maxIndexY! {
let randomFunc = [self.firstFunction, self.secondFunction, self.thirdFunction]
let randomResult = Int(arc4random_uniform(UInt32(randomFunc.count)))
return randomFunc[randomResult]()
}

The count in my For loop is not incrementing

When running my code, I am getting a number of 1's printing to the console rather than 1,2,3,4,5....
Some help with why this is happening would be great, I'm having trouble figuring it out.
The idea is to loop through the Calendar names until finding the 'Travel' calendar.
func checkCalendarExists(){
var eventCalendars = store.calendarsForEntityType(EKEntityTypeEvent) as [EKCalendar]
for i in eventCalendars {
var count = 0
var calendarCount = eventCalendars.count
if i.title != "Travel" && count != calendarCount
{
++count
println(count)
}
else if i.title == "Travel"
{
// do something
}
else
{
aMethod()
}
}
}
Your count variable is not being incremented because it is declared inside the loop and initialized to the value zero at the beginning of each iteration. For your code to work as expected you have to move var count = 0 outside the for loop.
Your count variable does get incremented, but it resets to zero every time the for loop runs its sequence.
It's always advised to declare and assign incrementing variables outside loops.
Please change your code to (I am initializing var count = 0 before the loop)
func checkCalendarExists(){
var eventCalendars = store.calendarsForEntityType(EKEntityTypeEvent) as [EKCalendar]
var count = 0
for i in eventCalendars {
var calendarCount = eventCalendars.count
......
......
......
else
{
aMethod()
}
}
}
ALXGTV's answer explains why you have that unexpected behavior.
Your code can be optimized though - rather than manually handling a counter variable, I recommend using the enumerate function, which returns a (index, value) at each iteration:
for (index, calendar) in enumerate(eventCalendars) {
...
}
Also this variable:
var calendarCount = eventCalendars.count
is populated at each iteration, always with the same value. It would be more efficient if it is moved before the loop, making it immutable:
let calendarCount = eventCalendars.count
for (index, calendar) in enumerate(eventCalendars) {
...
}
Last, I would prefer using a flag for the not found condition, handling it outside the loop:
func checkCalendarExists() {
var eventCalendars = store.calendarsForEntityType(EKEntityTypeEvent) as [EKCalendar]
var found = false
let calendarCount = eventCalendars.count
for (index, calendar) in enumerate(eventCalendars) {
if calendar.title == "Travel" {
// do something
found = true
break // This stops the loop
} else {
println(index + 1)
}
}
if !found {
aMethod()
}
}

Find Object with Property in Array

is there a possibility to get an object from an array with an specific property? Or do i need to loop trough all objects in my array and check if an property is the specific i was looking for?
edit: Thanks for given me into the correct direction, but i have a problem to convert this.
// edit again: A ok, and if there is only one specific result? Is this also a possible method do to that?
let imageUUID = sender.imageUUID
let questionImageObjects = self.formImages[currentSelectedQuestion.qIndex] as [Images]!
// this is working
//var imageObject:Images!
/*
for (index, image) in enumerate(questionImageObjects) {
if(image.imageUUID == imageUUID) {
imageObject = image
}
}
*/
// this is not working - NSArray is not a subtype of Images- so what if there is only 1 possible result?
var imageObject = questionImageObjects.filter( { return $0.imageUUID == imageUUID } )
// this is not working - NSArray is not a subtype of Images- so what if there is only 1 possible result?
You have no way to prove at compile-time that there is only one possible result on an array. What you're actually asking for is the first matching result. The easiest (though not the fastest) is to just take the first element of the result of filter:
let imageObject = questionImageObjects.filter{ $0.imageUUID == imageUUID }.first
imageObject will now be an optional of course, since it's possible that nothing matches.
If searching the whole array is time consuming, of course you can easily create a firstMatching function that will return the (optional) first element matching the closure, but for short arrays this is fine and simple.
As charles notes, in Swift 3 this is built in:
questionImageObjects.first(where: { $0.imageUUID == imageUUID })
Edit 2016-05-05: Swift 3 will include first(where:).
In Swift 2, you can use indexOf to find the index of the first array element that matches a predicate.
let index = questionImageObjects.indexOf({$0.imageUUID == imageUUID})
This is bit faster compared to filter since it will stop after the first match. (Alternatively, you could use a lazy sequence.)
However, it's a bit annoying that you can only get the index and not the object itself. I use the following extension for convenience:
extension CollectionType {
func find(#noescape predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Self.Generator.Element? {
return try indexOf(predicate).map({self[$0]})
}
}
Then the following works:
questionImageObjects.find({$0.imageUUID == imageUUID})
Yes, you can use the filter method which takes a closure where you can set your logical expression.
Example:
struct User {
var firstName: String?
var lastName: String?
}
let users = [User(firstName: "John", lastName: "Doe"), User(firstName: "Bill", lastName: "Clinton"), User(firstName: "John", lastName: "Travolta")];
let johns = users.filter( { return $0.firstName == "John" } )
Note that filter returns an array containing all items satisfying the logical expression.
More info in the Library Reference
Here is a working example in Swift 5
class Point{
var x:Int
var y:Int
init(x:Int, y:Int){
self.x = x
self.y = y
}
}
var p1 = Point(x:1, y:2)
var p2 = Point(x:2, y:3)
var p3 = Point(x:1, y:4)
var points = [p1, p2, p3]
// Find the first object with given property
// In this case, firstMatchingPoint becomes p1
let firstMatchingPoint = points.first{$0.x == 1}
// Find all objects with given property
// In this case, allMatchingPoints becomes [p1, p3]
let allMatchingPoints = points.filter{$0.x == 1}
Reference:
Trailing Closure
Here is other way to fetch particular object by using object property to search an object in array.
if arrayTicketsListing.contains({ $0.status_id == "2" }) {
let ticketStatusObj: TicketsStatusList = arrayTicketsListing[arrayTicketsListing.indexOf({ $0.status_id == "2" })!]
print(ticketStatusObj.status_name)
}
Whereas, my arrayTicketsListing is [TicketsStatusList] contains objects of TicketsStatusList class.
// TicketsStatusList class
class TicketsStatusList {
internal var status_id: String
internal var status_name: String
init(){
status_id = ""
status_name = ""
}
}

Immutable array on a var?

I am getting the error:
Immutable value of type 'Array Character>' only has mutating members of name removeAtIndex()
The array should have contents because that removeAtIndex line is in a loop who's condition is if the count > 1
func evaluatePostFix(expression:Array<Character>) -> Character
{
var stack:Array<Character> = []
var count = -1 // Start at -1 to make up for 0 indexing
if expression.count == 0 {
return "X"
}
while expression.count > 1 {
if expression.count == 1 {
let answer = expression[0]
return answer
}
var expressionTokenAsString:String = String(expression[0])
if let number = expressionTokenAsString.toInt() {
stack.append(expression[0])
expression.removeAtIndex(0)
count++
} else { // Capture token, remove lefthand and righthand, solve, push result
var token = expression(count + 1)
var rightHand = stack(count)
var leftHand = stack(count - 1)
stack.removeAtIndex(count)
stack.removeAtIndex(count - 1)
stack.append(evaluateSubExpression(leftHand, rightHand, token))
}
}
}
Anyone have any idea as to why this is? Thanks!
Because all function parameters are implicitly passed by value as "let", and hence are constant within the function, no matter what they were outside the function.
To modify the value within the function (which won't affect the value on return), you can explicitly use var:
func evaluatePostFix(var expression:Array<Character>) -> Character {
...
}

Resources