Swift: assigning function to variable
The postfix .self
expression just refers to the object it's an instance of. Kind of like .this
in other languages. For types in particular, it tells the compiler that you're referring to the type itself, rather than instructing it to create a new instance of that type. If you'd like to know more, you can read all about it in the docs here. While useful in a lot of cases, it's not really needed here.
As for your problem, when you assign:
var pendingFunction = ((Double, Double) -> Double).self
You're assigning the type of a particular sort of function as the value of the variable. From that, Swift infers that the type of the variable should be Type
. Then later when you try to assign an actual function fitting that type as the value, it throws an error because it's expecting a type, not a function.
Instead of assigning a type as value, you want to declare the variable with that type as its type:
var pendingFunction: ((Double, Double) -> Double)
Here's an example of the whole thing:
var pendingFunction: ((Double, Double) -> Double)
func myAdditionFunction (first: Double, second: Double) -> Double {
return first + second
}
pendingFunction = myAdditionFunction
print(pendingFunction(1,2)) // prints "3.0"
Assigning function to a variable in swift strange behavior
This appears to be a bug in the playground. It works in a project without trouble.
It can be simplified, though (I realize this probably isn't your real code, but it offers a good example of better approaches):
func swapper(inout arr: [Int]){
(arr[0], arr[arr.count - 1]) = (arr[arr.count - 1], arr[0])
}
//let myFunctionPointer : (inout [Int])->Void = swapper
let myFunctionPointer = swapper // There's no real reason for a type here
var x = [1,2,3]
myFunctionPointer(&x)
println(x)
Note that putting arr
at the end of your function is not a good practice. Swift does not return the last value computed, so this line does nothing at all (but create some confusion).
EDIT: Actually, it can be even a little simpler than that (I didn't realize this would work until I tried it):
func swapper(inout arr: [Int]){
swap(&arr[0], &arr[arr.count-1])
}
How To Store Swift function in a variable
You have to help the compiler decide which function you want because it does not distinguish between parameter names when deciding if a function's signature is valid for assignment.
You can disambiguate your intent by being specific on the parameter names
let c: (left :String) -> () = cars(left:)
let c2: (right:String) -> () = cars(right:)
Assign method (function of an object) to a variable or how to pass a parameter to unit tests
It turns out that for each instance method a type has, there's a
corresponding static method that lets you retrieve that instance
method as a closure, by passing an instance as an argument.
For example: [3, 2, 1].sort() == Array.sort([3, 2, 1])
Interesting fact, but pretty useless in our case, because
Partial application of 'mutating' method is not allowed.
So as long as I can't pass a mutating method as a parameter, I will pass an enumeration object:
extension Array where Element == Int {
mutating func sort(_ algorithm: SortAlgorithm) {
switch algorithm {
case .bubble: bubbleSort()
case .selection: selectionSort()
}
}
}
enum SortAlgorithm {
case bubble
case selection
}
As for second part of the question I think the best answer is inheritance:
// MARK: - Basic UnitTest Class
class SortingTest: XCTestCase {
static var algorithm: SortAlgorithm!
override static func tearDown() {
algorithm = nil
super.tearDown()
}
func testSorting1() {
var a = [9, 2, 5, 3, 8, 1, 4, 7, 6]
a.sort(Self.algorithm)
XCTAssertEqual(a, [1, 2, 3, 4, 5, 6, 7, 8, 9])
}
func testSorting2() {
var a = [4, 3, 2, 1]
a.sort(Self.algorithm)
XCTAssertEqual(a, [1, 2, 3, 4])
}
......
// MARK: - Inherited UnitTest Classes
class BubbleTest: SortingTest {
override static func setUp() {
super.setUp()
algorithm = .bubble
}
}
class SelectionTest: SortingTest {
override static func setUp() {
super.setUp()
algorithm = .selection
}
}
Everything is ready for nicely calling tests for appropriate sorting algorithm:
extension enum SortAlgorithm {
func runTests() {
switch self {
case .bubble: BubbleTest.defaultTestSuite.run()
case .selection: SelectionTest.defaultTestSuite.run()
}
}
}
SortAlgorithm.bubble.runTests()
P.S. Thank @DávidPásztor and @matt for hints :)
Assign print function to a variable
I believe you've found a known bug (or limitation) of the Swift compiler.
The built-in print
function has three parameters. Parameter #1 is unlabeled and is type String ...
(variadic). Parameter #2 has label separator
, is type String
, and has a default value. Parameter #3 has label terminator
, is type String
, and has a default value. Since parameters #2 and #3 have default values, you can call it like print("hello")
.
Closures (like myPrint
) cannot use labeled parameters. So myPrint
takes three unlabeled parameters. Parameter #1 is type String ...
(variadic). Parameter #2 is type String
. Parameter #3 is also type String
. Closure parameters cannot have default values, so myPrint
requires all three parameters. You cannot call it like myPrint("hello")
, because you haven't passed anything for parameters #2 and #3 and they do not (and cannot) have default values.
In Swift, a variadic parameter (like parameter #1 of print
and myPrint
) consumes all arguments until in reaches a label. If you try to call myPrint("hello", " ", "\n")
, all three arguments will be assigned to parameter #1, and nothing will be assigned to parameters #2 and #3.
Since you cannot have labeled parameters in a closure, there is no way to call your myPrint
closure, because there is no way to pass values for parameters #2 and #3.
This is a known limitation. See SR-2475 and SR-494.
Assign variable to function - Swift 3
Your syntax is a bit mangled.
- Add underscores to the func signature to improve readability.
- Pass in a variable only when you want to overwrite the default.
Recode this sample func to not always return 1, but return what was passed into it (or the default).
func foo(_ bar: Int = 10) -> Int {
return bar
}
var demo = foo() // returns the default of 10
var test = foo(1) // returns the parameter passed in, which is 1
let result = demo - test
EDIT: The actual question was lost in the errors fixed above. The OP is to have foo(bar:) be a computed property. So the final solution would be:
var _foo:Int = 10
var foo:Int {
get {
return _foo
}
set {
_foo = newValue
}
}
Tested in a viewDidLoad():
print(foo) // prints 10
foo = 1
print(foo) // prints 1
Please note:
- You cannot do anything like have a "constant default" to a computed property. Since this is an instance property, you set it once only.
- You cannot turn a function into a property. Yes, functions are first-class citizens in Swift, but this only means you can "treat them like a variable" by passing them into another function.
- I tried a few variations (adding "= 10" to the declaration, making the Int an Optional, removing the get from things, and it either doesn't build or crashes.
If you really need to have a default of 10, compute what is passed into things, and have it available globally, I recommend refactoring your concept to use one or the other of these solutions.
Swift function parameters as local variables
Before Swift 3, Swift used to have them. You used to be able to do something like this:
func f(var x: Int) { // note the "var" modifier here
x += 1
print(x) // prints 2
}
var a = 1
f(a)
print(a) // prints 1
But it was removed in Swift 3, via SE-0003. The Swift community decided that this is not a good feature. The motivations given in that proposal are:
var
is often confused withinout
in function parameters.var
is often confused to make value types have reference semantics.- Function parameters are not refutable patterns like in if-, while-, guard-, for-in-, and case statements.
use variable to store function in swift as pointer function in Obj-C or C++
To solve the error
Class 'MenuScene' has no initializers
you have two options: change the declaration of animationFunction
to make it an Optional
or create a designated initializer for MenuScene
where you assign a value to the non-Optional `animationFunction.
To solve the second error of incompatible types, you need to change the declaration of animationFunction
since currently it's type is TimeInterval
and not a function type. From the error message it seems you want a function of type (TimeInterval)->()
, namely one that accepts a single input parameter of type TimeInterval
and returns Void
.
To fix both errors, simply modify the declaration of animationFunction
to make it Optional
and have the required function type:
private var animationFunction: ((TimeInterval)->())?
Related Topics
Uisearchcontroller in Navigationitem iOS 11 Apple Way
Swiftui: Detect Finger Position on MAC Trackpad
Uitableviewcell Height Auto Layout Not Working on iOS 10
Realitykit - Set Text Programmatically of an Entity of Reality Composer
One-Way Platform Collisions in Sprite Kit
How to Highlight a Uitextview's Text Line by Line in Swift
How to Override Layerclass in Swift
Difference Between Switch Cases "@Unknown Default" and "Default" in Swift 5
Combining Two Conditions in Nspredicate
Swift Check Type Against a Generic Type
How to Make a Swift Framework Submodule Really Private
Swift - Converting from Unsafepointer<Uint8> with Length to String
Variable P Passed by Reference Before Being Initialized
How to Fix Error: This Class Is Not Key Value Coding-Compliant for the Key Tableview.'