Can property wrapper have default parameter values? - swift

Is it possible to implement property wrapper that is initialized by either explicit values or predefined defaults? So that, given example:
#propertyWrapper
struct Wrapper<Value> {
private(set) var value: Value!
private var x: Int
private var y: Int
var wrappedValue: Value {
get { value }
set { value = newValue }
}
init(wrappedValue value: Value,
withX x: Int = 10,
withY y: Int = 20) {
self.x = x
self.y = y
self.wrappedValue = value
}
}
is able to be initialized in any of the following ways
#Wrapper
var allDefaults = ...
#Wrapper(withX: 30)
var explicitX = ...
#Wrapper(withY: 40)
var explicitY = ...
#Wrapper(withX: 50, withY: 60)
var allExplicit = ...
The above example works in swift 5.1 only in case all of the optional parameters are explicitly initialized, as in last #Wrapper example.
In any other case this results in error: Abort trap: 6

This is a compiler bug that has been resolved: SR-11480

Related

Can you explain the output of the following Swift Projected Value?

#propertyWrapper
struct smallNumber {
private var num: Int
private var maximum: Int
var projectedValue: Bool
var wrappedValue: Int {
get { return num }
set {
if num > maximum {
num = maximum
projectedValue = true
}
else {
num = newValue
projectedValue = false
}
}
}
init() {
num = 0
maximum = 12
projectedValue = false
}
init(wrappedValue: Int) {
maximum = 12
projectedValue = false
num = min(wrappedValue, maximum)
}
init(wrappedValue: Int, maximum: Int) {
self.maximum = maximum
projectedValue = false
num = max(wrappedValue, maximum)
}
}
struct Rectangle {
#smallNumber var height: Int
#smallNumber var width: Int
var area: Int {
get {
return height * width
}
}
}
var x = Rectangle()
x.height = 9
x.width = 89
//x.width = 78
print(x.$height, x.$width, x.area)
Hi, I am learning swift and I am having trouble in the above code. In the swift reference(Projected Values), it's written that if we set the value of x greater than 12 then projectedValue becomes true. But after running the above code x.$width prints false. After removing the comment at 2nd last line x.$width prints true. Can someone explain me how is it working?
You copied the code incorrectly.
You have
if num > maximum {
but need
if newValue > maximum {

Cannot use mutating getter on immutable value: 'self' is immutable error

I'm trying to reuse an older piece of Swift code, but getting an error 'Cannot use mutating getter on immutable value: 'self' is immutable error'. Xcode wanted to add 'mutating' before the func, and offered to do so through a 'fix'. So the error is gone there but still remains at the 'Text' statements.
import SwiftUI
struct ContentView: View {
typealias PointTuple = (day: Double, mW: Double)
let points: [PointTuple] = [(0.0, 31.98), (1.0, 31.89), (2.0, 31.77), (4.0, 31.58), (6.0, 31.46)]
lazy var meanDays = points.reduce(0) { $0 + $1.0 } / Double(points.count)
lazy var meanMW = points.reduce(0) { $0 + $1.1 } / Double(points.count)
lazy var a = points.reduce(0) { $0 + ($1.day - meanDays) * ($1.mW - meanMW) }
lazy var b = points.reduce(0) { $0 + pow($1.day - meanDays, 2) }
lazy var m = a / b
lazy var c = meanMW - m * meanDays
lazy var x : Double = bG(day: 3.0)
lazy var y : Double = bG(day: 5.0)
lazy var z : Double = bG(day: 7.0)
mutating func bG(day: Double) -> Double {
return m * day + c
}
var body: some View {
VStack {
Text("\(x)")
Text("\(y)")
Text("\(z)")
}
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
Because when you call x inside the struct, it's not clear whether the contentView itself is mutable or not. A value type gets mutable only when it is defined as a var.
So it would help if you wrapped it with an immutable value before using it inside a builder function inside the struct.
like this:
func xValue() -> Double {
var mutatableSelf = self
return mutatableSelf.x
}
var body: some View {
VStack {
Text("\(xValue())")
}
}
💡Note: Lazy property's value will be associated on the first call and this mutates the object. So they are considered as mutating
A getter cannot mutate
This is mainly a design Swift is enforcing with its getters. The principle is:
The getters should not mutate the object. Because developers may not be expecting that. They should only expect a change when you're using the setter or calling a mutating function. A getter is neither of them.
The following example works as expected:
struct Device {
var isOn = true
}
let a = Device()
let b = a
print(a.isOn)
When we print, we get the value of a.isOn. Both a,b are identical.
Yet in the following example, the getter will have a side-effect. It won't even compile. But let's just assume that it did and see what happens.
struct Device2 {
var x = 3
var isOn: Bool {
x = 5
return true
}
}
let a = Device2()
let b = a
print(a.isOn)
When we print, we get the value of a.isOn. However this time the a,b are no longer identical. a.x will now be 5, because a copy-on-write would have happened, while b.x would still be 3.
Swift has an architecture that doesn't allow "getters to mutate an object".
Exceptions
The Swift architecture has two exceptions to this rule:
use lazy
use #State or some other property wrapper
Lazy is mutating:
struct Device2 {
lazy var x : Double = 3.0
func log() {
print(x)
}
}
Even thought print(x) will mutate x upon getting the value of x, it's fine because x a lazy property.
You might be wondering what's different between lazy var x = 5 and var x = 5 and the answer is that the latter has the value of x set upon initialization of the struct...
SwiftUI - special case
Because the body variable is a computed property, you can't mutate/set variables. There's a way around that though.
Mark the variable with a #State property wrapper.
Example. The following code won't compile:
struct ContentView: View {
var currentDate = Date()
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
Text("\(currentDate)")
.onReceive(timer) { input in
currentDate = input // ERROR: Cannot assign to property: 'self' is immutable
}
}
}
Yet the following will, just because it has #State
struct ContentView: View {
#State var currentDate = Date()
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
Text("\(currentDate)")
.onReceive(timer) { input in
currentDate = input
}
}
}
For more on that see here

Read-Only properties

I need help with "read-only" in swift. I tried various ways, but simply couldn't figure out how to compile it without errors. Here's the question and what i thought of.
Create a read-only computed property named isEquilateral that checks to see whether all three sides of a triangle are the same length and returns true if they are and false if they are not.
var isEquilateral: Int {
}
If you want a "read-only" stored property, use private(set):
private(set) var isEquilateral = false
If it is a property calculated from other properties, then, yes, use computed property:
var isEquilateral: Bool {
return a == b && b == c
}
For the sake of completeness, and probably needless to say, if it is a constant, you’d just use let:
let isEquilateral = true
Or
struct Triangle {
let a: Double
let b: Double
let c: Double
let isEquilateral: Bool
init(a: Double, b: Double, c: Double) {
self.a = a
self.b = b
self.c = c
isEquilateral = (a == b) && (b == c)
}
}
Something like this? (as suggested by #vacawama in the comments)
struct Triangle {
let edgeA: Int
let edgeB: Int
let edgeC: Int
var isEquilateral: Bool {
return (edgeA, edgeB) == (edgeB, edgeC)
}
}
Let's test it
let triangle = Triangle(edgeA: 5, edgeB: 5, edgeC: 5)
triangle.isEquilateral // true
or
let triangle = Triangle(edgeA: 2, edgeB: 2, edgeC: 1)
triangle.isEquilateral // false
A read-only property is a property with getter but no setter. It is always used to return a value.
class ClassA {
var one: Int {
return 1
}
var two: Int {
get { return 2 }
}
private(set) var three:Int = 3
init() {
one = 1//Cannot assign to property: 'one' is a get-only property
two = 2//Cannot assign to property: 'two' is a get-only property
three = 3//allowed to write
print(one)//allowed to read
print(two)//allowed to read
print(three)//allowed to read
}
}
class ClassB {
init() {
var a = ClassA()
a.one = 1//Cannot assign to property: 'one' is a get-only property
a.two = 2//Cannot assign to property: 'two' is a get-only property
a.three = 3//Cannot assign to property: 'three' setter is inaccessible
print(a.one)//allowed to read
print(a.two)//allowed to read
print(a.three)//allowed to read
}
}

Is it possible to set a variable via its own setter method? [duplicate]

With this simple class I am getting the compiler warning
Attempting to modify/access x within its own setter/getter
and when I use it like this:
var p: point = Point()
p.x = 12
I get an EXC_BAD_ACCESS. How can I do this without explicit backing ivars?
class Point {
var x: Int {
set {
x = newValue * 2 //Error
}
get {
return x / 2 //Error
}
}
// ...
}
Setters and Getters apply to computed properties; such properties do not have storage in the instance - the value from the getter is meant to be computed from other instance properties. In your case, there is no x to be assigned.
Explicitly: "How can I do this without explicit backing ivars". You can't - you'll need something to backup the computed property. Try this:
class Point {
private var _x: Int = 0 // _x -> backingX
var x: Int {
set { _x = 2 * newValue }
get { return _x / 2 }
}
}
Specifically, in the Swift REPL:
15> var pt = Point()
pt: Point = {
_x = 0
}
16> pt.x = 10
17> pt
$R3: Point = {
_x = 20
}
18> pt.x
$R4: Int = 10
You can customize the set value using property observer. To do this use 'didSet' instead of 'set'.
class Point {
var x: Int {
didSet {
x = x * 2
}
}
...
As for getter ...
class Point {
var doubleX: Int {
get {
return x / 2
}
}
...
Setters/getters in Swift are quite different than ObjC. The property becomes a computed property which means it does not have a backing variable such as _x as it would in ObjC.
In the solution code below you can see the xTimesTwo does not store anything, but simply computes the result from x.
See Official docs on computed properties.
The functionality you want might also be Property Observers.
What you need is:
var x: Int
var xTimesTwo: Int {
set {
x = newValue / 2
}
get {
return x * 2
}
}
You can modify other properties within the setter/getters, which is what they are meant for.
To elaborate on GoZoner's answer:
Your real issue here is that you are recursively calling your getter.
var x:Int
{
set
{
x = newValue * 2 // This isn't a problem
}
get {
return x / 2 // Here is your real issue, you are recursively calling
// your x property's getter
}
}
Like the code comment suggests above, you are infinitely calling the x property's getter, which will continue to execute until you get a EXC_BAD_ACCESS code (you can see the spinner in the bottom right corner of your Xcode's playground environment).
Consider the example from the Swift documentation:
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
Notice how the center computed property never modifies or returns itself in the variable's declaration.
In order to override setter and getter for swift variables use the below given code
var temX : Int?
var x: Int?{
set(newX){
temX = newX
}
get{
return temX
}
}
We need to keep the value of variable in a temporary variable, since trying to access the same variable whose getter/setter is being overridden will result in infinite loops.
We can invoke the setter simply like this
x = 10
Getter will be invoked on firing below given line of code
var newVar = x
Update: Swift 4
In the below class setter and getter is applied to variable sideLength
class Triangle: {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) { //initializer method
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get { // getter
return 3.0 * sideLength
}
set(newValue) { //setter
sideLength = newValue / 4.0
}
}
Creating object
var triangle = Triangle(sideLength: 3.9, name: "a triangle")
Getter
print(triangle.perimeter) // invoking getter
Setter
triangle.perimeter = 9.9 // invoking setter
You are recursively defining x with x. As if someone asks you how old are you? And you answer "I am twice my age". Which is meaningless.
You must say I am twice John's age or any other variable but yourself.
computed variables are always dependent on another variable.
The rule of the thumb is never access the property itself from within the getter ie get. Because that would trigger another get which would trigger another . . . Don't even print it. Because printing also requires to 'get' the value before it can print it!
struct Person{
var name: String{
get{
print(name) // DON'T do this!!!!
return "as"
}
set{
}
}
}
let p1 = Person()
As that would give the following warning:
Attempting to access 'name' from within it's own getter.
The error looks vague like this:
As an alternative you might want to use didSet. With didSet you'll get a hold to the value that is was set before and just got set to. For more see this answer.
Try using this:
var x:Int!
var xTimesTwo:Int {
get {
return x * 2
}
set {
x = newValue / 2
}
}
This is basically Jack Wu's answer, but the difference is that in Jack Wu's answer his x variable is var x: Int, in mine, my x variable is like this: var x: Int!, so all I did was make it an optional type.
Setters and getters in Swift apply to computed properties/variables. These properties/variables are not actually stored in memory, but rather computed based on the value of stored properties/variables.
See Apple's Swift documentation on the subject: Swift Variable Declarations.
Here is a theoretical answer. That can be found here
A { get set } property cannot be a constant stored property. It should be a computed property and both get and set should be implemented.
Update for Swift 5.1
As of Swift 5.1 you can now get your variable without using get keyword. For example:
var helloWorld: String {
"Hello World"
}
I don't know if it is good practice but you can do something like this:
class test_ancestor {
var prop: Int = 0
}
class test: test_ancestor {
override var prop: Int {
get {
return super.prop // reaching ancestor prop
}
set {
super.prop = newValue * 2
}
}
}
var test_instance = test()
test_instance.prop = 10
print(test_instance.prop) // 20
Read more

Property getters and setters

With this simple class I am getting the compiler warning
Attempting to modify/access x within its own setter/getter
and when I use it like this:
var p: point = Point()
p.x = 12
I get an EXC_BAD_ACCESS. How can I do this without explicit backing ivars?
class Point {
var x: Int {
set {
x = newValue * 2 //Error
}
get {
return x / 2 //Error
}
}
// ...
}
Setters and Getters apply to computed properties; such properties do not have storage in the instance - the value from the getter is meant to be computed from other instance properties. In your case, there is no x to be assigned.
Explicitly: "How can I do this without explicit backing ivars". You can't - you'll need something to backup the computed property. Try this:
class Point {
private var _x: Int = 0 // _x -> backingX
var x: Int {
set { _x = 2 * newValue }
get { return _x / 2 }
}
}
Specifically, in the Swift REPL:
15> var pt = Point()
pt: Point = {
_x = 0
}
16> pt.x = 10
17> pt
$R3: Point = {
_x = 20
}
18> pt.x
$R4: Int = 10
You can customize the set value using property observer. To do this use 'didSet' instead of 'set'.
class Point {
var x: Int {
didSet {
x = x * 2
}
}
...
As for getter ...
class Point {
var doubleX: Int {
get {
return x / 2
}
}
...
Setters/getters in Swift are quite different than ObjC. The property becomes a computed property which means it does not have a backing variable such as _x as it would in ObjC.
In the solution code below you can see the xTimesTwo does not store anything, but simply computes the result from x.
See Official docs on computed properties.
The functionality you want might also be Property Observers.
What you need is:
var x: Int
var xTimesTwo: Int {
set {
x = newValue / 2
}
get {
return x * 2
}
}
You can modify other properties within the setter/getters, which is what they are meant for.
To elaborate on GoZoner's answer:
Your real issue here is that you are recursively calling your getter.
var x:Int
{
set
{
x = newValue * 2 // This isn't a problem
}
get {
return x / 2 // Here is your real issue, you are recursively calling
// your x property's getter
}
}
Like the code comment suggests above, you are infinitely calling the x property's getter, which will continue to execute until you get a EXC_BAD_ACCESS code (you can see the spinner in the bottom right corner of your Xcode's playground environment).
Consider the example from the Swift documentation:
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
Notice how the center computed property never modifies or returns itself in the variable's declaration.
In order to override setter and getter for swift variables use the below given code
var temX : Int?
var x: Int?{
set(newX){
temX = newX
}
get{
return temX
}
}
We need to keep the value of variable in a temporary variable, since trying to access the same variable whose getter/setter is being overridden will result in infinite loops.
We can invoke the setter simply like this
x = 10
Getter will be invoked on firing below given line of code
var newVar = x
Update: Swift 4
In the below class setter and getter is applied to variable sideLength
class Triangle: {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) { //initializer method
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get { // getter
return 3.0 * sideLength
}
set(newValue) { //setter
sideLength = newValue / 4.0
}
}
Creating object
var triangle = Triangle(sideLength: 3.9, name: "a triangle")
Getter
print(triangle.perimeter) // invoking getter
Setter
triangle.perimeter = 9.9 // invoking setter
You are recursively defining x with x. As if someone asks you how old are you? And you answer "I am twice my age". Which is meaningless.
You must say I am twice John's age or any other variable but yourself.
computed variables are always dependent on another variable.
The rule of the thumb is never access the property itself from within the getter ie get. Because that would trigger another get which would trigger another . . . Don't even print it. Because printing also requires to 'get' the value before it can print it!
struct Person{
var name: String{
get{
print(name) // DON'T do this!!!!
return "as"
}
set{
}
}
}
let p1 = Person()
As that would give the following warning:
Attempting to access 'name' from within it's own getter.
The error looks vague like this:
As an alternative you might want to use didSet. With didSet you'll get a hold to the value that is was set before and just got set to. For more see this answer.
Try using this:
var x:Int!
var xTimesTwo:Int {
get {
return x * 2
}
set {
x = newValue / 2
}
}
This is basically Jack Wu's answer, but the difference is that in Jack Wu's answer his x variable is var x: Int, in mine, my x variable is like this: var x: Int!, so all I did was make it an optional type.
Setters and getters in Swift apply to computed properties/variables. These properties/variables are not actually stored in memory, but rather computed based on the value of stored properties/variables.
See Apple's Swift documentation on the subject: Swift Variable Declarations.
Here is a theoretical answer. That can be found here
A { get set } property cannot be a constant stored property. It should be a computed property and both get and set should be implemented.
Update for Swift 5.1
As of Swift 5.1 you can now get your variable without using get keyword. For example:
var helloWorld: String {
"Hello World"
}
I don't know if it is good practice but you can do something like this:
class test_ancestor {
var prop: Int = 0
}
class test: test_ancestor {
override var prop: Int {
get {
return super.prop // reaching ancestor prop
}
set {
super.prop = newValue * 2
}
}
}
var test_instance = test()
test_instance.prop = 10
print(test_instance.prop) // 20
Read more