Return a boolean from a closure - swift

I have been searching in Swift documentation and googling but can't find how to return a value from a block like this:
func checkIfplayerFellDown() -> Bool {
self.enumerateChildNodesWithName("brick", usingBlock: {
(node: SKNode!, stop: UnsafeMutablePointer <ObjCBool>) -> Bool in
if (node.position.y < self.player.position.y) { return false }
})
return true
}
The problem is because I do not understand blocks. I usually use them like this:
world.enumerateChildNodesWithName("name") {node, stop in
if (node.position.y < self.size.height*0.5) {
node.removeFromParent()
}
}
How can I return a boolean from any of this closures? I know I should probably use a syntax out somewhere and I tried some things but none of them worked because I have no idea how the blocks even work.
Any explanation or an example of how this should be done is appreciated.

Use a local variable (outside the block but inside the method) to pass the result out of the block, and also set stop to true when you want to stop the iteration:
func playerFellDown() -> Bool {
var result = true
self.enumerateChildNodesWithName("brick") { (child, stopOut) in
if child.position.y < self.player.position.y {
result = false
stopOut.memory = true
}
}
return result
}

Related

How to check the string doesn’t contain any letters in swift?

i have trouble during making the letter checker, my code is like this: if !containLetters(“1234h”){print(“pass”)}
my function is
func containsOnlyNum(input: String) -> Bool {
var ok = false
for chr in input {
for check in "1234567890.-"{
if chr == check{
ok = true
}
}
if ok != true{
return false
}
}
return true
}
If I check for “h” then didn’t pass, but if i check for ”1h” then it still pass! Please help me to fix this problem. I will give a big thank for anyone who helped me
The simplest way to fix the algorithm is this way:
func containsOnlyNum(input: String) -> Bool {
// check every character
for chr in input {
var isNum = false
for check in "1234567890.-"{
if chr == check {
isNum = true
// if we have found a valid one, we can break the iteration
break
}
}
if !isNum {
return false
}
}
return true
}
print(containsOnlyNum(input: "1234")) // true
print(containsOnlyNum(input: "1234h")) // false
However, then you can directly simplify it to:
func containsOnlyNum(input: String) -> Bool {
return input.allSatisfy { chr in
"1234567890.-".contains(chr)
}
}
which does exatly the same but uses allSatisfy and contains functions, which represent the logical operators ALL and EXISTS.
However, programmers normally use regular expressions for similar tasks:
func containsOnlyNum(input: String) -> Bool {
return input.range(of: "^[0-9.\\-]+$", options: .regularExpression) != nil
}
You can check that a string contains only the characters you're interested in like this:
extension String {
var containsOnlyNum: Bool {
let wanted = CharacterSet.decimalDigits
.union(CharacterSet(charactersIn: "-."))
return unicodeScalars
.allSatisfy(wanted.contains)
}
}
"-12.34".containsOnlyNum // true
"A1234".containsOnlyNum // false
But if you are interested in numbers, then this is a problem:
"-12.-34.".containsOnlyNum // true
Instead, you can just try casting the string to a double and see if it is a number or not
Double("1234") != nil // true, a number
Double("-1.234") != nil // true, a number
Double("A1234") != nil // false, not a number
Double("-12.-34.") != nil // false, not a number
Which is almost right unless you don't want this case:
Double("1234e2") != nil // true, a number
But you can use both checks if you don't want to allow that, or else if you are able to parse a Double from the input you can just do the cast.

In Swift functions, why 'return' must be outside for loop, when function includes a for loop with if statement inside the loop? [duplicate]

This question already has answers here:
Swift function compiler error 'missing return'
(3 answers)
Closed 2 years ago.
Assume a returning function:
func check(scores: [Int]) -> Bool {
for score in scores {
if score < 80 {
return false
}
}
return true
}
The above code works perfectly. However the below code doesn't. An error pops up saying: Missing return in a function expected to return 'Bool'. I know this error very well but I don't know why it is popping up here:
func check(scores: [Int]) -> Bool {
for score in scores {
if score < 80 {
return false
}
else {
return true
}
}
}
Why the 'return false' can be inside the if condition {} but the 'return true' can not be inside the else {} and must be completely outside the for loop ... ...? I ask this specially because the below code works perfectly and the 'return true' is inside the else {}
func isPassingGrade(for scores: [Int]) -> Bool {
var total = 0
for score in scores {
total += score
}
if total >= 500 {
return true
} else {
return false
}
}
Any insight is highly appreciated and kind regards.
This is because of the assumption that the for loop may not execute at all if scores is empty here
func check(scores: [Int]) -> Bool {
for score in scores {
if score < 80 {
return false
}
else {
return true
}
}
}
so the function need to know what it should return in that case , your first and last blocks are ok as there is a guarantee that some Bool value will be returned in case the for loop is executed or not
In case you ask that the sent array will not be empty , yes but at compile time there is no way to know that , hence the error
If scores is empty, the body of the for loop will not be executed, and the check function will not return anything. It does, however, promise to return a Bool, and that's why it's an error.

Swift Bool Function return will never executed

I want to create a code which can determine whether the character is one of the symbols in my list.
var symbols = ["+","-"]
func issymbol(last:String ) -> Bool{
return true
for i in 0...(symbols.count){
if last == symbols[i]{
return false
}
}
}
You need to add return true at the end and it will execute if last == symbols[i]{ never met. So update your code as shown below:
func issymbol(last:String) -> Bool{
for i in 0...(symbols.count){
if last == symbols[i]{
return false
}
}
return true
}
issymbol(last: "+") //false
Or you can use contains property for that:
func issymbol(last:String) -> Bool{
return !symbols.contains(last)
}
issymbol(last: "+") // false
issymbol(last: "1") // true
No code execute after return keyword. so I update your code try this
var symbols = ["+","-"]
func issymbol(last:String ) -> Bool{
for value in symbols {
if last == value {
return true
}
}
return false
}
Functions only execute until they reach a return statement. Xcode detected that the rest of the code in that function won't be executed, because your function will always return after the first line. You probably meant something like this:
var symbols = ["+","-"]
func issymbol(last:String ) -> Bool{
for i in 0...(symbols.count){
if last == symbols[i]{
return false
}
}
return true
}
Because the return statement is after the for loop, the for loop can execute. This function will return true if the string you pass in is not in the symbols array.
There are a lot issues in this code.
The line return true returns immediately so the check won't be performed (the error message).
The line for i in 0...(symbols.count) will crash because the index starts at 0 and the last index is symbols.count - 1. Alternatively you can write for i in 0..<symbols.count.
The best syntax is not to write an index based loop:
for symbol in symbols { if last == symbol ...
If the item is found the code returns false rather than true.
The code doesn't return a Bool after the loop if the item was not found (will cause another error).
The correct code is
let symbols = ["+","-"]
func issymbol(last: String) -> Bool {
for i in 0...symbols.count - 1 {
if last == symbols[i] {
return true
}
}
return false
}
However this can be reduced to
func issymbol(last: String) -> Bool {
return symbols.contains(last)
}

Swift: how to call the function which calls a random function?

I have four functions which I want to activate randomly. This is the code I have so far, which I get no errors from. However, I get an error "Expression Resolves to an unused function" when I try to call the createSquare() function.
func createSquare () -> () -> () {
let squares = [self.squareOne, self.squareTwo, self.squareThree, self.squareFour]
let randomSquare = Int(arc4random_uniform(UInt32(squares.count)))
return squares[randomSquare]
}
if gameIsOn == true {
createSquare()
}
How can I successfully call the function createSquare()?
func squareOne() {
square1.isHidden = false
}
And squareTwo, squareThree, squareFour are all similar with different numbers.
The problem is that createSquare() returns a closure that you never invoke (that's the "unused function" mentioned in the warning message).
You need to call the function, for example, like this:
let randomFunction = createSquare()
randomFunction()
You can also call it right away with a somewhat less readable syntax:
createSquare()()
func createSquare() {
let randomNumber = Int.random(in: 0...3)
if randomNumber == 0 {
squareOne()
} else if randomNumber == 1 {
squareTwo()
} else if randomNumber == 2 {
squareThree()
} else if randomNumber == 3 {
squareFour()
}
}

Swift Compare Set

I try to check FB permissions, like this:
let permissions = ["user_friends", "public_profile"];
NSLog("Contains Permissions:%#", FBSDKAccessToken.currentAccessToken()
.permissions);
NSLog("Requested Permissions:%#", permissions);
if(!FBSDKAccessToken.currentAccessToken().permissions.contains(permissions)){
return false;
}else{
return true;
}
But it always returns false. Anyone an idea why ?
EDIT: Log output
Contains Permissions:{(
"user_friends",
"public_profile"
)}
2015-10-28 23:01:59.723: Requested Permissions:(
"user_friends",
"public_profile"
)
The contains() function you've used checks to see of any element of 'current Access Token' permissions is an array of permissions. It is always false because the token permissions are strings, NOT arrays of strings.
If the two arrays need to have exactly the same elements, then the absolute simplest code would be:
let permissions = ["user_friends", "public_profile"];
NSLog("Contains Permissions:%#", FBSDKAccessToken.currentAccessToken()
.permissions);
NSLog("Requested Permissions:%#", permissions);
tokenPermissions = FBSDKAccessToken.currentAccessToken().permissions as? [String]
return tokenPermissions != nil && tokenPermissions.sort().elementsEqual(permissions.sort())
You might first object to using sort(), perhaps as overkill, but otherwise you will be traversing the two lists of permissions multiple time so sort() ends up not being such a concern.
Another option is to iterate over the tokenPermissions and ensure that every one is in permissions. Like such:
for tokenPermission in tokenPermissions {
if !permissions.contains (tokenPermission) {
return false
}
}
return true
Or, if you got really ambitious and need to do a lot of sequence testing:
extension SequenceType {
public func any (#noescape predicate: (Self.Generator.Element) -> Bool) -> Bool {
for elt in self {
if predicate (elt) { return true }
}
return false
}
public func all (#noescape predicate: (Self.Generator.Element) -> Bool) -> Bool {
for elt in self {
if !predicate (elt) { return false }
}
return true
}
}
and then your code contains:
return tokenPermissions.all { permissions.contains ($0) }
And, finally, if the two arrays of permissions are actually sets of permissions then you can use
return Set(tokenPermissions).elementsEqual(Set(permissions))
So you've got a bunch of options.
What you are probably looking for is
let permissions = ["user_friends", "public_profile"]
let tokenPermissions = FBSDKAccessToken.currentAccessToken().permissions
NSLog("Contains Permissions:%#", tokenPermissions)
NSLog("Requested Permissions:%#", permissions)
guard let tokenPermissions = tokenPermissions as? Set<String> else {
return false
}
return tokenPermissions.isSupersetOf(permissions)
For the isSupersetOf(_:) syntax see Swift Collection Types, you need to cast the untyped NSSet into a Swift Set<String> for the function to work.
You can change:
if(!FBSDKAccessToken.currentAccessToken().permissions.contains(permissions))
to:
if FBSDKAccessToken.currentAccessToken().permissions.containsObject("user_friends") && FBSDKAccessToken.currentAccessToken().permissions.containsObject("public_profile")
Solution for alot of set, see example code:
let permisssion = NSSet(array:["user_friends", "public_profile"])
let test = NSSet(array: ["user_friends", "email","public_profile"])
if permisssion.isSubsetOfSet(test as Set<NSObject>) {
print("true")
} else {
print("false")
}