Having Trouble executing function but not for loop it is in - ios

I am trying to create a function that can take in a function and an Int(numberOfTimes) and then call on doFunctionXTimes() a certain number of times. However, it only prints out "Hello Ethan" once opposed to five times. Here is my code:
func doFunctionXTimes(numberOfTimes: Int,function: Any) {
for _ in 1...numberOfTimes {
function
}
}
func sayHello(name: String) {
print("Hello \(name)")
}
doFunctionXTimes(5, function: sayHello("Ethan"))
//this code prints "Hello Ethan"
However, if change _ to i in the for loop in doFunctionXTimes() and then add a print(i) statement either above or below where I call the function, it will print out all of the numbers from 1 to 5. How can I make it so the function is called on as many times as the print(i) statement is called on and printed. Thank you. Here is my edited code printing i.
func doFunctionXTimes(numberOfTimes: Int,function: Any) {
for i in 1...numberOfTimes {
print(i)
function
// or the print(i) statement can here. It does not affect the output.
}
}
func sayHello(name: String) {
print("Hello \(name)")
}
doFunctionXTimes(5, function: sayHello("Ethan"))
// this code prints out "Hello Ethan" and then 1 2 3 4 5
Any help or advice is great and I hope this helps future viewers.

Have a look at the following code:
doFunctionXTimes(5, function: sayHello("Ethan"))
The sayHello("Ethan") part is a function call. So when the line of code runs, it first calls this function - before entering doFunctionXTimes. Then inside your code, you have:
function
This doesn't actually call the function (it's similar to putting 0 on a line by itself). To achieve what you want, you need a closure, which will "wrap around" the function that you want to call:
func doFunctionXTimes(numberOfTimes: Int,function: (() -> Void)) {
for _ in 1...numberOfTimes {
function()
}
}
func sayHello(name: String) {
print("Hello \(name)")
}
doFunctionXTimes(5, function: { sayHello("Ethan") })
Now function is passed as { sayHello("Ethan") }, and sayHello won't be called until the function is called.
Note that function is now defined as () -> Void, which means it's a func that takes no parameters and returns no value. (I put extra braces around the definition because I find it improves clarity)

You can also set it up so that you can add to the number of times it repeats simply by repeating a var set to the function.
func sayHello(name: String)
{
print("Hello \(name)")
}
func repeatDoFunctionXTimes(number: Int, forFunction function:(()-> Void))-> (() ->Int) {
var runFor = number
var i = 0;
func repeater() -> Int {
while i < runFor {
print(i)
function()
i++
}
runFor += 1
return runFor
}
return repeater
}
var repeatFive = repeatDoFunctionXTimes(5, forFunction: {sayHello("Ethan")})
repeatFive()
If you type in repeatFive() again it will print 6 times and so forth.

Related

Swift - How can I force every method in a class to call specific function?

In other words, I'd like to find a way to avoid typing code used repeatedly in every class method like the following example.
Codes:
class SampleClass {
func common() {
print("It's done")
}
func first() {
print("First fucntion is excuted")
self.common()
}
func second() {
print("First fucntion is excuted")
self.common()
}
func third() {
print("First fucntion is excuted")
self.common()
}
}
Result:
SampleClass().first()
// First fucntion is excuted
// It's done
SampleClass().second()
// Second fucntion is excuted
// It's done
SampleClass().third()
// Third fucntion is excuted
// It's done
As you can see method common() is executed in every class methods.
What I want to do here is rather than writing common() method in every method, making all methods run it automatically.
Are there any functions or patterns to do this in Swift? If so, please let me know.
Thanks!
A possible way is to call common and pass a closure
class SampleClass {
func common(action: #escaping () -> Void) {
action()
print("It's done")
}
func first() { print("First function is executed") }
func second() { print("Second function is executed") }
func third() { print("Third function is executed") }
}
let sample = SampleClass()
sample.common(action: sample.first)
// First function is executed
// It's done
sample.common(action: sample.second)
// Second function is executed
// It's done
sample.common(action: sample.third)
// Third function is executed
// It's done

Swift. How to return a function from a closure

I have a question regarding closure
function AA(){
localPlayer.authenticateHandler{
//…
if trigger {
retrun
}
}
dosomething()
}
In the above code,
I want to write a code that wants to return to the AA() function when the trigger is satisfied in the authenticateHandler closure that is called by an asynchronous callback.
The result of the code above is
When trigger occurs, only the closure is returned and the dosomething() method is executed below.
Is there any way
I have short English skills, but thank you for your help.
Closure does not support return statement. Instead use completion block inside main thread to perform the task:
i.e
function AA( completion: #escaping (Result<[Return Type], Error>) -> Void) {
localPlayer.authenticateHandler{
//…
if trigger {
DispatchQueue.main.async {
completion(//Whatever Return Value)
}
}
dosomething()
}
}
Closure does not support return statement.
Do it this way.
here i used string comparison to show how completion block will work.
func call() {
compareString(str1: "hey", str2: "hey") { isMatch in
if isMatch! { //Trigger
self.doSomething()
}
}
}
func compareString(str1:String,str2:String,completion:#escaping ((Bool?) -> Void)) {
if str1 == str2 {
completion(true)
}else {
completion(false)
}
}
func doSomething() {
}
It doesn’t work that way. A synchronous function can’t wait for the result of an asynchronous function. Give AA a callback closure and call it when authenticateHandler returns.

Set function as variable in function declaration

I want to have function as variable in function declaration and than call that variable within declared function. How to do it in Swift?
Pseudo code:
let something = 0
func one() {
print("one")
}
// Definition
func two( funcVariable: Void, number: Int) {
print("\(number)")
funcVariable() // here I want to call variable function
}
// Call
two(funcVariable: one(), number: somethhing)
How to do it?
Example code appreciated.
Here is how you do it:
let something = 0
func one() {
print("one")
}
// Definition
func two(funcVariable: () -> Void, number: Int) {
print("\(number)")
funcVariable()
}
// Call
two(funcVariable: one, number: something)

Completion block not called (Swift)

I have written a function with a completion block as an argument. When I call this function in my view controller, the completion block is not executed. This is my first time writing my own custom completion block, so I may be making just an easy mistake. Here is the function in my model:
func iterateThrough2(userInput: String, completion: (completed: Bool) -> Bool) -> Double {
while numberOfCharactersDone < userInput.characters.count {
let startIndex = userInput.startIndex.advancedBy(numberOfCharactersDone)
let letterIndex = userInput.characters[startIndex]
let letter = String(letterIndex)
if isLetter(letter) {
isALetter(letter, input: userInput)
}
else {
isNotLetter(letter)
}
numberOfCharactersDone++
}
return total
}
And in my view controller, I call it:
#IBAction func calculate(sender: UIButton) {
if let text = self.enteredText.text {
let result = calculator.iterateThrough2(text, completion: { (completed) -> Bool in
if completed {
print("good")
return true
}
else {
print("not good")
return false
}
})
self.outputLabel.text = String(result)
calculator.resetData()
}
}
The function does successfully return a double, as it should, and it is working otherwise. It just doesn't call the closure. What am I doing wrong?
Do I have to include and specify in my method when exactly I want the closure to be ran? I read here: https://www.codefellows.org/blog/writing-completion-blocks-with-closures-in-swift and tried to call the completion block at the end of my method like:
completion(completed: completed)
return total
but I got an error "use of unresolved identifier "completed""

How to specify completion handler with one function not return [duplicate]

Error: Cannot convert the expression type (String, MyType) to ()
From the following code
Test(method: {[weak self] (message: String) in self?.callback(message)}, instance: self)
and if I add a return statement, it works, and the error goes away
Test(method: {[weak self] (message: String) in self?.callback(message); return}, instance: self)
Not sure how to handle the above without having to have the dummy return statement, any advise.
Here's my class Test
public class Test {
private var instance: AnyObject?
private var method: ((message: String) -> ())?
public init(method: (String -> ())?, instance: AnyObject) {
}
}
Edit
I've done a playground based minimalistic example (please copy paste for a test)
class Test {
private var _method: ((String) -> ())?
weak private var _instance: AnyObject?
init(method: (String -> ())?, instance: AnyObject?) {
_method = method
_instance = instance
}
}
class Another {
func register() {
//this doesn't need a return
Test(method: {(message: String) in self.callback(message)}, instance: self)
//this needs a return once I add [weak self]
Test(method: { [weak self] (message: String) in self?.callback(message); return}, instance: self)
}
func callback(message: String) {
println(message)
}
}
Not sure how to handle the above without having to have the dummy return statement, any advise.
You have solved the problem beautifully. Anonymous functions automatically use a one-line function body as a return value, so to prevent that from causing a type mismatch with the expected return type (Void) you have to add another line of code so that it is not a one-line function body. The dummy return statement, which itself returns Void, is a great way to handle it; I would just use that and move on. There are some snazzier workarounds but what you have is precisely what I would do.
EDIT: To understand the source of the type mismatch, try this:
struct Test {
func voider() -> Void {}
}
let testMaybe = Optional(Test())
let result = testMaybe?.voider()
Now result is not a Void; it's an Optional wrapping a Void. That is what's happening to you; a Void is expected but your one-line anonymous function returns an Optional wrapping a Void. By adding another line that returns Void explicitly, you solved the problem.
The implicit return is returning the result of your callback() method. That return value conflicts with the closure's return value of void. You thus need an explicit, if ugly, return.

Resources