I would like to store a reference to a primitive type (Double, Int) in Swift, so that i one variable is changed, the other one is changed, too. Here is an example:
class MyClass {
var value: Double?
}
var myValue = 1.0
var instance = MyClass()
instance.value = myValue // <-- how to set a reference?
myValue = 2.0 // => I want instance.value to change to 2.0
instance.value = 3.0 // => I want myValue to change to 3.0
Is that possible?
You can use class-holder:
class Ref<T> {
var value: T
init(_ value: T) {
self.value = value
}
}
Or try to read about In-Out Parameters and maybe it can help you in some way:
In-Out Parameters
Variable parameters, as described above, can only be changed within
the function itself. If you want a function to modify a parameter’s
value, and you want those changes to persist after the function call
has ended, define that parameter as an in-out parameter instead.
You write an in-out parameter by placing the inout keyword at the
start of its parameter definition. An in-out parameter has a value
that is passed in to the function, is modified by the function, and is
passed back out of the function to replace the original value.
You can only pass a variable as the argument for an in-out parameter.
You cannot pass a constant or a literal value as the argument, because
constants and literals cannot be modified. You place an ampersand (&)
directly before a variable’s name when you pass it as an argument to
an inout parameter, to indicate that it can be modified by the
function.
func swapTwoInts(inout a: Int, inout _ b: Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// prints "someInt is now 107, and anotherInt is now 3"
The closest thing in Swift I can think of like this is inout variables. They are allowed in Swift as a constructor argument (but saving them to a variable stops them from working):
class Demo {
var value: Double
init(inout value: Double) {
value++
self.value = value
}
}
var value = 1.0
let demo = Demo(value: &value)
print(value) // 2.0
demo.value++
print(value) // 2.0
Thus, I don't believe the syntax you want is possible. However, maybe inout parameters might be a substitute if you can re-work the problem.
I use this:
#propertyWrapper public struct Inout<T> {
public init(wrappedValue: T) {
storage = .init(value: wrappedValue)
}
private let storage: Storage
public var wrappedValue: T {
nonmutating get { storage.value }
nonmutating set { storage.value = newValue }
}
private class Storage {
init(value: T) {
self.value = value
}
var value: T
}
}
Example:
struct Example {
init(value: Inout<Int>) {
_value = value
}
#Inout var value: Int
func performAction() {
value += 19
}
}
let value = Inout(wrappedValue: 50)
let example = Example(value: value)
example.performAction()
print(value.wrappedValue) // 69
Related
I want to pass to setter as argument one of predefined functions (in enum maybe or static) or custom function in closure.
like UIColor to UIView.backgroundColor (i can set .black or UIColor(...)). How can I do it with my custom class?
class MyClass {
var fun: ((String)->Void)?
}
var obj = MyClass()
obj.fun = {print($0)} . // It works now
obj.fun = .predefinedFunc // It's how i want to be able do
What you seem to want to do is "implicit member access". Unfortunately, this is not possible on closure types like (String) -> Void, because it only works on enums, as well as types with static members. (String) -> Void doesn't and can't have any static members.
It seems like what you want is simply a bunch of predefined functions. This can be done with an enum:
enum Function {
case predefinedFunc1
case predefinedFunc2
case predefinedFunc3 // name these properly!
var closure: (String) -> Void {
switch self {
case .predefinedFunc1: return { print($0) }
case .predefinedFunc2: ...
case .predefinedFunc3: ...
}
}
}
And then you'll be able to do:
class MyClass {
var fun: Function?
}
var obj = MyClass()
obj.func = .predefinedFunc1
If you also want to include an option to use a custom function, add an extra case with an associated value:
enum Function {
...
case custom((String) -> Void)
var closure: (String) -> Void {
switch self {
case .predefinedFunc1: return { print($0) }
...
case .custom(let f): return f
}
}
}
view.backgroundColor = .black
works because black is a static property of struct UIColor. The right-hand side is called an “implicit member expression,” see for example What is the Swift syntax " .bar" called?.
Function types are neither classes nor structs, and you cannot define a static property for a function type. Therefore an identical syntax is not possible.
What you can do is to define a “wrapper” struct for the function, with static properties for the predefined functions. Here is a simple example:
struct Fun {
let f: (String) -> Void
init(_ f: #escaping (String) -> Void) {
self.f = f
}
// Predefined functions:
static var printer = Fun( { print($0) } )
// ...
}
class MyClass {
var fun: Fun?
}
And then you can do
let obj = MyClass()
obj.fun = Fun( { print($0) } ) // set to custom function
obj.fun = .printer // set to predefined function
This approach also allows to extend the wrapper type by more predefined functions:
extension Fun {
static var printReversed = Fun( { print($0.reversed()) } )
}
// ...
obj.fun = .printReversed
Please define the func same as you callback func or nameless fun, then you can pass it as an argument.
class MyClass {
var fun: ((String)->Void)?
}
//MARK:- you have to provide the same param and return type in your predefined func.
func printer(Str :String)->Void{
print(Str)
}
var obj = MyClass()
obj.fun = {print($0)}
obj.fun = printer
What's the magic attached to SwiftUI's #State property wrapper which means I can I do this?:
struct A {
#State var s: String
}
let a = A(s: "string") //uses a synthesised init for `A` which allows me to init A with the underlying type of `A.s` - a `string`
whereas if I roll my own #propertyWrapper, I can't?
#propertyWrapper
struct Prop<Value> {
var value: Value
var wrappedValue: Value {
get { value }
set { value = newValue }
}
}
struct B {
#Prop var s: String
}
let b = B(s: "string") // Compiler error: `Cannot convert value of type 'String' to expected argument type 'Prop<String>'`
let b = B(s: Prop(value: "string")) // Works, but is ugly
As documented in:
Swift evolution proposals
Deep in the language guide
... you can get the compiler to do this for you, as it does with #State - just add a specific magic init(wrappedValue:) to your property wrapper definition:
#propertyWrapper
struct Prop<Value> {
var value: Value
var wrappedValue: Value {
get { value }
set { value = newValue }
}
// magic sauce
init(wrappedValue: Value) {
self.value = wrappedValue
}
}
struct B {
#Prop var s: String
}
let b = B(s: "string") // Now works
Incidentally, this also allows you to assign default values for your wrapped properties in the struct definition:
struct B {
#Prop var s: String = "default value" // Works now; would have thrown a compiler error before
}
I want to conform to a protocol, as well as to hide its conformed properties to be accessed (declare them as private).
Consider the following:
protocol P {
var value: String { get }
init(value: String)
}
class C: P {
var value: String
required init(value: String) {
self.value = value
}
}
I would create a C object:
let myObject = C(value: "Hello World")
myObject.value = "New Value"
Based on that I have 2 questions:
Now, if I tried to declare value as private:
private var value: String { get }
the compiler will throw an error:
'private' modifier cannot be used in protocols
with a fix suggestion to replace the private with internal.
How can I prevent value from being accessible by saying myObject.value? if there is no way, what's the reason of this limitation?
Conforming to
protocol P {
var value: String { get }
init(value: String)
}
requires a gettable property value with default access. If write access to the
property in the conforming class should be restricted to the class itself
then you can declare it as in Swift readonly external, readwrite internal property:
class C: P {
private(set) var value: String
required init(value: String) {
self.value = value
}
}
let myObject = C(value: "Hello World")
print(myObject.value) // OK
myObject.value = "New Value" // Error: Cannot assign to property: 'value' setter is inaccessible
And if the property should only be set in initializers then make it
a constant:
class C: P {
let value: String
required init(value: String) {
self.value = value
}
}
let myObject = C(value: "Hello World")
print(myObject.value) // OK
myObject.value = "New Value" // Error: Cannot assign to property: 'value' is a 'let' constant
In Swift 2 it is possible to do the following:
class SomeType {
static let singletonInstance = SomeType()
func someFunction(var mutableParameter: SomeType = SomeType.singletonInstance) {
...
}
}
However in Swift 3 the var keyword will be removed for function parameters in favour of inout. I have not been able to achieve the same result as the above using the inout keyword.
class SomeType {
static let singletonInstance = SomeType()
func someFunction(inout mutableParameter: SomeType = SomeType.singletonInstance) {
...
}
}
Instead I receive an error of "Default argument value of type 'SomeType' cannot be converted to type 'inout SomeType'"
My question is whether it is possible to use inout with default value?
The two keywords you're talking about, inout and var, are very different.
From Apple Documentation:
In-out parameters are passed as follows:
When the function is called, the value of the argument is copied.
In the body of the function, the copy is modified.
When the function returns, the copy’s value is assigned to the original argument.
Therefore you can't give a default value to an inout parameter, as it would make the inout property completely useless.
What you can do is receive a normal (constant) parameter with a default value, and declare a new var with the same name this way (code from the Swift Evolution's Removing var from Function Parameters Proposal, with the addition of the default parameter):
func foo(i: Int = 5) {
var i = i
// now you can change i as you'd like
}
Anyone who needs a default inout parameter may consider such solution:
class SomeType {
static let singletonInstance = SomeType()
func someFunction(inout mutableParameter: SomeType) {
...
}
// Declare function without 'mutableParameter':
func someFunction() {
someFunction(SomeType.singletonInstance)
}
}
When you specify the default value for the parameter, the Swift compiler automatically generates a function without the parameter, for you. In this solution we do it manually.
You could create a second function signature to "emulate" a default value
func foo() {
var v: Int = 0 // your default value
foo(bar: &v)
}
func foo(bar: inout Int) {
// do stuff
}
I think var value: T = nil is causing error below because XCode can't convert nil value to the generic type T.
class Node<T> {
var value: T = nil
var next: Node
init(value: T) {
self.value = value
self.next = Node()
}
init() {
self.next = Node()
}
}
The error message reads
Could not find an overload for '_coversion' that accepts the supplied
arguments
Is there a way to assign nil value to a variable in Swift?
You need to declare the variable as optional:
var value: T? = nil
Unfortunately this currently seems to trigger an unimplemented compiler feature:
error: unimplemented IR generation feature non-fixed class layout
You can work around it by declaring T with a type constraint of NSObject:
class Node<T:NSObject> {
var value: T? = nil
var next: Node
init(value: T) {
self.value = value
self.next = Node()
}
init() {
self.next = Node()
}
}
Try using
var value: T? = nil
The question mark makes the variable an optional, meaning that it can either have a value or be nil.