I have a computed property called count. I was going use this to get the count of two different arrays inside of a singleton; however, when I try to call the function, I'm not allowed to select the computed properties inside of the property. If this isn't allowed in Swift then I will just create a new function to handle the same thing. Just thought it would be much simpler to call ".count"
The setup for the computed property:
private var completeTasks: [Task] = []
private var incompleteTasks: [Task] = []
public var count: Int {
var complete: Int {
get {
return completeTasks.count
}
}
var incomplete: Int {
get {
return incompleteTasks.count
}
}
}
and when I try to call the property:
Related
I would like to create a property wrapper for CurrentValueSubject. I have done this like that:
#propertyWrapper
public class CurrentValue<Value> {
public var wrappedValue: Value {
get { projectedValue.value }
set { projectedValue.value = newValue }
}
public var projectedValue: CurrentValueSubject<Value, Never>
public init(wrappedValue: Value) {
self.projectedValue = CurrentValueSubject(wrappedValue)
}
}
This works but there is a little thing I would like to change with it - use struct instead of class. The problem with using struct for this is that sometimes I could get Simultaneous accesses error. And I know why, this happens when in sink from this publisher I would try to read the value from wrapped value. So for example with code like this:
#CurrentValue
let test = 1
$test.sink { _ in
print(self.test)
}
And I more or less know why - because when projectedValue executes its observation, wrapped value is still in process of setting its value. In class this is ok, because it would just change the value, but with struct it actually modifies the struct itself, so Im trying to write and read from it at the same time.
My question is - is there some clever way to overcome this, while still using struct? I don't want to dispatch async.
Also I know that #Projected works similarly to this propertyWrapper, but there is a big difference - Projected executes on willSet, while CurrentValueSubject on didSet. And Projected has the same issue anyway.
I know that I can read the value inside the closure, but sometimes Im using this with various function calls, that might eventually use self.test instead.
Try my implementation
#propertyWrapper
class PublishedSubject<T> {
var wrappedValue: T {
didSet {
subject.send(wrappedValue)
}
}
var projectedValue: some Publisher<T, Never> {
subject
}
private lazy var subject = CurrentValueSubject<T, Never>(wrappedValue)
init(wrappedValue: T) {
self.wrappedValue = wrappedValue
}
}
How can I do this right? (Error: Variable used within its own initial value):
private var cars = [Car]() {
get { return cars }
}
...works for:
private var connection:Bool! {
get { return connection }
}
Your variable
cars
is a computed property. That been said, it doesnt store any value. For your example you will need to create a variable. Lest called it
private var localCars = [Car]()
This variable is the one that will store all the values you need and then you can use the computed property to get all the information you need from cars like this.
private var cars:Cars! {
get { return localCars }
}
You can also use the set in your computed propert to store the value to localCars
private var cars:Cars! {
get { return localCars }
set { localCars = newValue }
}
If you want to learn what its a computer property check this page. It explains them really well.
Why declare readonly property in protocol if we can set value trough class or struct? I can not understand usage of this.
In "The Swift Programming Book" version 2.0
“If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for the property to be also settable if this is useful for your own code.”
So that it's not settable from outside the class/struct. Imagine your API returned some instance of a protocol that has a get and set property (in your protocol), then anyone getting this instance would be able to set the value!
Also get and set properties can't be constants:
protocol RWProt {
var value : Int { get set }
}
// Error: Type 'Value' does not conform to protocol 'RWProt'
struct Value : RWProt {
let value = 0
}
This however works:
protocol Read {
var value : Int { get }
}
struct Value : Read {
var value = 0
mutating func change() {
value++
}
}
The protocol only needs the value to be gettable, so get protocols properties are not get only but rather get or set
Okay, here is another example:
import Foundation
public protocol ExternalInterface {
var value : Int { get }
}
private struct PrivateStuff : ExternalInterface {
var value = 0
mutating func doSomePrivateChangingStuff() {
value = Int(arc4random())
}
}
public func getInterfaceToPrivateStuff() -> ExternalInterface {
var stuff = PrivateStuff()
stuff.doSomePrivateChangingStuff()
return stuff
}
// In another file:
let interfaceToSomethingICantChange = getInterfaceToPrivateStuff()
// error: cannot assign to property: 'value' is a get-only property
interfaceToSomethingICantChange.value = 0
I ran into a problem when I was trying to "translate" some Objective-C code to Swift. I define Garage and Car in CoreData. Garage has a relationship to Car called cars. I have a masterviewcontroller to display "Garage" class and detailviewcontroller to display a NSArray of "car" class. Here is my code in Objective-C. I want to let cars = allobjects when it is nil; otherwise just return it.
#property (nonatomic, strong) NSArray* cars;
- (NSArray*) cars {
if (_cars == nil) {
_cars = self.garage.cars.allObjects;
}
return _cars;
}
However, in Swift, it does not have a underscore instance for property, and I cannot let cars == nil since "==" cannot be applied to operands of type [Car]. I tried to use the following code, but it gave me two errors: "attempting to access 'cars' within its own getter" and "cannot assign a value of type '[AnyObject]?' to a value of type '[Car]'"
var garage : Garage?
var cars : [Car] {
if let a = cars {
get {
cars = self.garage?.cars.allObjects
}
}
Any help is appreciated.
UPDATE/////////////////////////////////////////////
Here is the method I used to solve my problem.
private var _cars: [Car]?
var cars: [Car]?
{
get {
if _cars == nil {
_cars = self.garage?.cars.allObjects as? [Car]
}
return _cars
}
set {
_cars = cars
}
}
Thank you for all the help.
I might suggest just having a computed property:
var cars : [Car]? {
return garage?.cars.allObjects
}
And, remember to make cars variable and optional array.
Looks like you need a lazy property:
lazy var cars: [Car]? = self.garage?.cars.allObjects
Yes, you need a lazy var.
Your code will be (Swift 2.3):
lazy var cars: [Car]? = { [unowned self] in
return self.garage?.cars.allObjects
}()
The trick are the { and the [unowned self]
Lazy var in sintax instance the value just one time and keep it, maybe it's what you want.
Maybe you just need a wrapper to get each time the value of self.garage?.cars.allObjects in which case you need a computed var, not a lazy var with a static value
var cars: [Car]? {
get {
return self.garage?.cars.allObjects
}
}
In Swift, you would generally replace properties with variables (var); if a property can be set in you init method and stays unchanged after that, you would use (let).
In your case, you have your own "get" method. In Swift, when you have a getter or setter method, there is no backing variable. So what you do, you create one. Typically as a private variable with a leading underscore.
You should think about how you reset the variable to nil. Having a setter is not a good idea, because you only want to allow setting the variable to nil and nothing else. If it is only set to nil inside the class itself, you can set the variable with underscore to nil. Otherwise you might add a function like "resetCars".
And note that if you have a "get" method, but none of "set", "willSet" and "didSet", you can just write the set code without any getter. So a typical usage would be:
private var _cars: [Car]?
func resetCars () -> Void { _cars = nil } // To allow resetting outside the class
var cars: [Car] {
if _cars == nil {
_cars = cleverlyCalculatedNonNilValue()
}
return _cars
}
I want a lazily-initialized property whose initializer I can invoke again if I set the property to nil.
If I define my property this way:
lazy var object = { /*init code*/ }()
...and later invoke the property, the initializer is triggered once. However, if I set object to nil later in my program, the initializer is not invoked again. How can I do that in Swift?
I looked into computed properties but they don't actually store values, so whenever I invoke the variable, the computation or initialization always occurs. I want to compute only whenever the property is nil.
The lazy property initializer is responsible of initializing the property the first time it is accessed in read mode. Setting to nil has no effect on the initialization status - it's just a valid value the property stores.
You can mimic a lazy initialization with 3 properties:
a private initializer, implemented as a computed property (or a closure if you prefer)
a private backing property, storing the actual value
a non private property, which is the one you actually use in your code
The code looks like this:
class MyClass {
private var _myPropInitializer: Int {
return 5
}
private var _myProp: Int?
var myProp: Int? {
get {
if self._myProp == nil {
self._myProp = self._myPropInitializer
}
return _myProp!
}
set {
_myProp = newValue
}
}
}
the initializer property returns a computed value for the variable when it needs to be initialized, which is the 5 integer in the above example
myProp is an optional integer (to be able to store a nil):
on set, it will store the new value in the _myProp property
on get, if _myProp is nil, it invokes the initializer, assigning it to _myProp, and it returns its value
If you want to reuse that pattern, it's better to put everything in a class:
class Lazy<T> {
private let _initializer: () -> T
private var _value: T?
var value: T? {
get {
if self._value == nil {
self._value = self._initializer()
}
return self._value
}
set {
self._value = newValue
}
}
required init(initializer: () -> T) {
self._initializer = initializer
}
}
Note: a struct is not usable because setting a property inside a property getter is not allowed, whereas in a class it is.
Then you can use it as follows:
class MyTestClass {
var lazyProp: Lazy<Int>
init() {
self.lazyProp = Lazy( { return 5 } )
}
}
Some tests in playground:
var x = MyTestClass()
x.lazyProp.value // Prints {Some 5}
x.lazyProp.value = nil
x.lazyProp._value // Prints nil
x.lazyProp.value // Prints {Some 5}
The downside is that you have to access to the actual property as x.lazyProp.value and not as x.lazyProp.
Here's a lazy pattern I use when your object can only ever be nil or a computed value. It requires only 2 properties:
var todayPredicate: NSPredicate! {
set {
guard newValue == nil else {return} // could throw here if required
self._todayPredicateLazyBacker = nil
}
get {
guard self._todayPredicateLazyBacker == nil else {return self. _todayPredicateLazyBacker}
// construct your today predicate
let predicate = ...
self._todayPredicateLazyBacker = predicate
return self._todayPredicateLazyBacker
}
}
private var _todayPredicateLazyBacker: NSPredicate?
todayPredicate is constructed only once when it is read for the first time (lazy).
So why would you ever want to set todayPredicate to nil? In this example you are probably observing for the day changing because todayPredicate must always represent today. In your observer code you would simply do this, for example...
self.todayPredicate = nil
self.loadEvents()