I have a Property Wrapper Coordinates. In the class Car I am using the Coordinates Property Wrapper.
Questions:
How can I initialise Coordinates using Car's initialiser ?
How to make _coordinates accessible ? (I am not sure what is responsible for _coordinates)
Is there any documentation on the above ? Most examples I saw were using struct where the compiler generates / synthesises initialisers for the properties.
Note: I have added comments with the compilation errors that I am getting while attempting to do the above.
Code:
@propertyWrapper
struct Coordinates {
private var point : CGPoint
var wrappedValue : (Double, Double) {
get {
return (Double(point.x), Double(point.y))
}
set {
point = .init(x:newValue.0, y:newValue.1)
}
}
var value : CGPoint {
return point
}
init(_ tuple: (Double, Double) = (0, 0)) {
self.point = .init(x: tuple.0, y: tuple.1)
}
}
class Car {
@Coordinates var coordinates : (Double, Double)
init(tuple: (Double, Double)) {
//Compilation Error: 'self' used in property access 'coordinates' before all stored properties are initialized
self.coordinates = tuple
}
}
let car1 = Car(tuple: (10.22, 20.33))
//Compilation Error: _coordinates' is inaccessible due to 'private' protection level
print(car1._coordinates)
How to make _coordinates accessible ? (I am not sure what is responsible for _coordinates)
Accessible from where? Currently it's not possible to access the property wrapper outside the type because it automatically is a private stored property.
You could however write a different property and expose the wrapper.
var exposedCoordinates: Coordinates {
_coordinates
}
Is there any documentation on the above ? Most examples I saw were using struct where the compiler generates / synthesises initialisers for the properties.
Alternative solution, just make everything manually!
class Car {
// FIXME: Change to `internal(wrapper) @Coordinates` when possible
internal var _coordinates: Coordinates
var coordinates: (Double, Double) {
get {
_coordinates.wrappedValue
}
set {
_coordinates.wrappedValue = newValue
}
}
init(tuple: (Double, Double)) {
self._coordinates = Coordinates(tuple)
}
}
@DevAndArtist Thank you so much for the detailed explanation and reference link.
I suppose the reason for the initialisation compilation error was because I was trying to set a computed property (wrappedValue) in the initialiser before self.point was set.
The following code from the proposal documentation explains the use of _ variable:
@Lazy var foo = 1738 translates to:
private var _foo: Lazy<Int> = Lazy<Int>(wrappedValue: 1738)
var foo: Int {
get { return _foo.wrappedValue }
set { _foo.wrappedValue = newValue }
}
There is a small typo in the initialiser _Coordinates(tuple), I suppose it was Coordinates(tuple)
Just wondering if it would be possible for the compiler to infer the data type while declaring a property that uses a non-generic property wrapper.
Example 1 (works ok):
//(Double, Double) has to match the data type of the `wrappedValue`
@Coordinates var coordinates : (Double, Double)
Example 2 (compilation error):
//Compilation Error:
//Property type 'Int' does not match that of the 'wrappedValue' property of its wrapper type 'Coordinate'
@Coordinate var coordinates : Int
Based on the compilation error message, it seems like the compiler is expecting wrappedValue's data type.
As this is in the Using Swift category ... in this particular case Iām not really sure why are you using a property wrapper at all? It might be worth taking a moment to double-check this is what you want.
I think the code would be cleaner and clearer if Coordinates was just a simple struct with two properties, or you could consider using CGPoint directly.