Read once and then set to nil - swift

I'd like to implement such property, that it's value is available for reading only one time, and then the property should be set to nil.
I've implemented it in such way:
private var _readOnce: String?
var readOnce: String? {
get {
let value = _readOnce
_readOnce = nil
return value
}
set {
_readOnce = newValue
}
}
readOnce = "Andrej"
print("read once = \(readOnce)") // prints read once = Optional("Andrej")\n"
print("read once = \(readOnce)") // prints read once = nil\n"
But I'feel like using a separate property _readOnce is not the "swifty" / "most elegant" way to do it.
Does anyone know of a different way, that wouldn't require to use a separate property?
I can confirm that the above code works, it's only that I feel it could be more elegant with less lines to achieve the same behaviour.

I don't know that there's a way to avoid having a backing property, but what I'd probably do is to make a helper type to wrap up the behavior. Something like this:
struct OneTimeValue<T>
{
private var isUnread = true
private let value : T
init(_ value: T)
{
self.value = value
}
func get() -> T?
{
guard isUnread else {
return nil
}
self.isUnread = false
return self.value
}
}
You could also write this a little differently if you prefer, by nilling out value inside of get(), for example, but the general plan holds.
Then your class becomes:
class Miser
{
var readOnce : String?
{
return self._readOnce.get()
}
private let _readOnce = OneTimeValue("Can't touch this (twice)")
}
I've also used this pattern for a UserDefaultsValue (storage to/from user defaults) and a SynchronizedValue (read-write lock on a property) and I think it works well.

As far as I know it is not possible without a second variable. This is because computed properties do not store any data for the variable they represent:
In addition to stored properties, classes, structures, and
enumerations can define computed properties, which do not actually
store a value.
For non-computed properties, the only observers you can have are based upon the setting of the variable, not the getting (i.e. willSet and didSet)
Hope that helps!
EDIT:
It can be done with closures and property observers if you're careful:
This requires no other variables (instead the value is captured by the closure), but it is rather unclear — I wouldn't recommend it.
var readOnce: () -> String? = {nil} {
didSet{
readOnce = { [weak self, readOnce] in
self?.readOnce = {nil}
return readOnce()
}
}
}
readOnce() // returns nil
readOnce = {"Hi"}
readOnce() // returns optional wrapped "Hi"
readOnce() // returns nil
A more 'Swifty' answer for you :D

After Swift 5.1, We can use Property Wrapper
#propertyWrapper
struct ReturnAndFree<T> {
private var value: T?
init(wrappedValue: T?) {
value = wrappedValue
}
var wrappedValue: T? {
mutating get {
defer { value = nil }
return value
}
set {
value = newValue
}
}
}

Related

How can I define insert function for Set when Set is optional in Swift?

My goal is to be able insert new item to an optional set which this set has nil value before. For that reason i created this extension, but it does not work, and still I cannot insert a new item to a nil set.
extension Optional where Wrapped == Set<String> {
func myInsert(_ value: String) -> Self {
if let unwrappedSet: Set<String> = self {
var newSet: Set<String> = unwrappedSet
newSet.insert(value)
return newSet
}
else {
let set: Set<String>? = [value]
return set
}
}
}
use case:
func myTest() -> Set<String>? {
var set: Set<String>? = nil
set.myInsert("Hello")
return set
}
if let set: Set<String> = myTest() {
print(set)
}
I refuse to believe there is issue with my extension, and i think the issue is from xcode itself, look the function below it is same function but outside of extension, it does works!
func myInsert(set: Set<String>?, value: String) -> Set<String>? {
if let unwrappedSet: Set<String> = set {
var newSet: Set<String> = unwrappedSet
newSet.insert(value)
return newSet
}
else {
let set: Set<String>? = [value]
return set
}
}
use case:
let set: Set<String>? = nil
let newSet = myInsert(set: set, value: "Hello")
let newSet2 = myInsert(set: newSet, value: "World")
print(newSet2)
result:
Optional(Set(["Hello", "World"]))
From your test case code:
var set: Set<String>? = nil
set.myInsert("Hello")
you expect the variable set to change from nil to a wrapped Set<String> containing the String "Hello". In order for the value to modify itself, the func must be mutating.
Make myInsert a mutating func and assign the new set to self. Since myInsert is mutating, it doesn't need to return a value which your test is ignoring anyway:
extension Optional where Wrapped == Set<String> {
mutating func myInsert(_ value: String) {
if self == nil {
self = [value]
} else {
self?.insert(value)
}
}
}
Test
func myTest() -> Set<String>? {
var set: Set<String>? = nil
set.myInsert("Hello")
set.myInsert("Goodbye")
return set
}
if let set = myTest() {
print(set)
}
["Hello", "Goodbye"]
Making insert more usable
(Thanks to #LeoDabus for his suggestions)
We can make this work with a Set of any type and make it more like the original insert on Set by having it return a #discardableResult containing a tuple with a Bool indicating if a the value was inserted and the memberAfterInsert:
extension Optional where Wrapped: SetAlgebra {
#discardableResult
mutating func insert(_ newMember: Wrapped.Element) -> (inserted: Bool, memberAfterInsert: Wrapped.Element) {
if self == nil {
self = .init()
}
return self!.insert(newMember)
}
}
vacawama and Leo's answer is correct but you want to understand why your code doesn't work. I'll try to explain why does not work as you expected. The function you created "myInsert" defines a Set object, inserts the parameter value and returns the newly created Set object. The problem is you are not actually assigning the created Set object to actual Set variable (which is "self") that you are working on.
if let unwrappedSet: Set<String> = self {
var newSet: Set<String> = unwrappedSet // assigning nil valued "self" to a variable doesn't assign the original variable. Assigning nil to another variable makes that variable again nil. Both are equal (they are nil) but not same variables.
newSet.insert(value) // inserts value to second Set object not to "self". So still, your actual Set doesn't contains the given value.
return newSet // returns the value inserted Set object, not "self".
}
else {
let set: Set<String>? = [value]
return set
}
If we look at myTest() function you can see that your adding operation doesn't work on actual variable.
var set: Set<String>? = nil
set.myInsert("Hello") // at this point, myInsert function returns a new Set object with inserted given value. But this operation does not effect the original variable above. That means set variable is still nil
return set // returns nil variable.
I hope this helps.

Executiong closure on array modification

I have the following code:
class Note: NSObject {
}
struct Global {
static var notes: Array<Note> = [] {
didSet {
print("hi")
}
}
}
This prints "hi" if I add or remove an item from the array or if I do
Global.notes = []
Is there a way to print("hi") every time when one of the Note objects in the array is modified?
Thanks for your answers
Without changing the class to a struct, I have two basic ways to handle this.
This is the object you asked about
class Note: NSObject {
}
struct Global {
static var notes: Array<Note> = [] {
didSet {
print("hi")
}
}
}
Wrap Notes in a wrapper that is a struct to get the struct behavior.
extension Note {
struct Wrapper { let note: Note }
}
extension Global {
static var wrappedNotes = [Note.Wrapper]() {
didSet {
print("hi")
}
}
}
Global.wrappedNotes.append(Note.Wrapper(note: Note()))
Global.wrappedNotes[0] = Note.Wrapper(note: Note())
Global.wrappedNotes.remove(at: 0)
The other way is to create a note manager to wrap access to the array.
class NoteManager {
subscript(index: Int) -> Note {
get {
return values[index]
}
set {
defer { onUpdate() }
values[index] = newValue
}
}
func append(_ newNote: Note) {
defer { onUpdate() }
values.append(newNote)
}
func remove(at index: Int) -> Note {
defer { onUpdate() }
return values.remove(at: index)
}
private func onUpdate() {
print("hi")
}
private var values = [Note]()
}
extension Global {
static var managedNotes = NoteManager()
}
Global.managedNotes.append(Note())
Global.managedNotes[0] = Note()
Global.managedNotes.remove(at: 0)
As per #staticVoidMan comment , If you make your model , a struct, rather than a class, then the property observer didSet will work for your Note model's own properties as well.
import Foundation
struct Note {
var name: String
}
struct Global {
static var notes: Array<Note> = [] {
didSet {
print("hi")
}
}
}
Global.notes.append(Note(name: "Shubham"))
Global.notes.append(Note(name: "Bakshi"))
Global.notes[0].name = "Boxy"
This will print the following on the console :
hi
hi
hi
Swift Array is a struct, and structs are value-type which means they change completely when elements are added/removed/replaced. Hence when you add/remove/replace a Note, the didSet property observer gets called as the array has been set again.
However, as per you question:
Is there a way to print("hi") every time when one of the Note objects in the array is modified?
By this I am assuming that you want to do something when an element within this array is accessed and an internal property is modified.
This would have been fine if you were dealing with only value-type objects, i.e. had your Note object also been a struct, then changing anything inside one Note would have caused the array to change as well.
But your Note object is a class, i.e. reference-type, and stays as the same object even if it's internal elements change. Hence your array doesn't need to update and didSet does not get called.
Read: Value and Reference Types
KVO Solution:
Now... Since your Note is subclassing NSObject, you can use the KVO concept
As per the following working example, we observe only one property of the Note class.
If you want to observe more properties then you will need to observe those many more keypaths.
Example:
class Note: NSObject {
#objc dynamic var content = ""
init(_ content: String) {
self.content = content
}
}
class NoteList {
var notes: [Note] = [] {
didSet {
print("note list updated")
//register & save observers for each note
self.noteMessageKVOs = notes.map { (note) -> NSKeyValueObservation in
return note.observe(\Note.content, options: [.new, .old]) { (note, value) in
print("note updated: \(value.oldValue) changed to \(value.newValue)")
}
}
}
}
//array of observers
var noteMessageKVOs = [NSKeyValueObservation]()
}
let list = NoteList()
list.notes.append(Note("A")) //note list updated
list.notes.append(Note("B")) //note list updated
list.notes[0].content = "X" //note updated: A changed to X
list.notes[1].content = "Y" //note updated: B changed to Y
Notes:
NSObject is required for KVO
#objc dynamic is required to make a property observable
\Note.message is a keypath
noteMessageKVOs are required to keep the observers alive

Can I add associated object to Swift Struct?

I would like to add an additional property to the Swift String. I used this approach few times on objects, but it seems that it does not work on struct. Although, I don't get any error...
This is what I tried:
var str = "Hello, StackOverflow"
fileprivate struct AssociatedKeys {
static var myBool = "myBool"
}
extension String {
public var myBool: Bool {
get {
guard let myBoolObject = objc_getAssociatedObject(self, &AssociatedKeys.myBool) as? NSNumber else {
return false
}
return myBoolObject.boolValue // execution never reaches this line
}
set(value) {
let object = NSNumber(value: value)
objc_setAssociatedObject(self, &AssociatedKeys.myBool, object, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
str.myBool = true
print(str.myBool) // prints "false"
It prints out that it is false.
At first, I tried it without wrapping the Bool into NSNumber, but the result was the same.
Is this even possible to add an associated object to a struct at all? If not, can anyone tell me why?
Based on #Hamish's comment, I created the following solution to workaround the issue.
Preconditions:
Have a framework which proposes prefilled objects, the app works on these objects and the framework should know which of the properties are modified during the processing of this object later.
Not using looooong initializers to setup all properties of MyObject is a design decision.
In my example, the usage of the myObject is a dummy and shows what happens in the framework and what happens in the app.
// protocol is used, as we could handle more modifiable structs/classes in a common way
protocol PropertyState {
var isModified: Bool {get set}
}
internal struct ModifiableString : PropertyState {
var string: String
var isModified: Bool
}
class MyObject: PropertyState {
internal var _name = ModifiableString(string: "", isModified: false)
public var name: String {
get {
return _name.string
}
set(value) {
_name.string = value
_name.isModified = true
}
}
// + N similar properties (they can be other types than String, by implementing other structs, like ModifiableBool)
var isModified: Bool {
get {
return _name.isModified // || _myAnotherProperty.isModified
}
set(value) {
_name.isModified = value
// _myAnotherProperty.isModified = value
}
}
}
// internal filling of the object inside of the framework
let myObject = MyObject()
myObject.name = "originalValue"
print(myObject.isModified) // true
// filling the object with values ended, so we can set the state
myObject.isModified = false
print(myObject.isModified) // false
// the app can work with the object
// let myObject = Framework.getObject()
myObject.name = "modifiedValue"
// now the framework should now which properties are modified
print(myObject._name.isModified) // true

Get all key paths from a struct in Swift 4

Let's say I have that struct:
struct MyStruct {
let x: Bool
let y: Bool
}
In Swift 4 we can now access it's properties with the myStruct[keyPath: \MyStruct.x] interface.
What I need is a way to access all it's key paths, something like:
extension MyStruct {
static func getAllKeyPaths() -> [WritableKeyPath<MyStruct, Bool>] {
return [
\MyStruct.x,
\MyStruct.y
]
}
}
But, obviously, without me having to manually declare every property in an array.
How can I achieve that?
DISCLAIMER:
Please note that the following code is for educational purpose only and it should not be used in a real application, and might contains a lot of bugs/strange behaviors if KeyPath are used this way.
Answer:
I don't know if your question is still relevant today, but the challenge was fun :)
This is actually possible using the mirroring API.
The KeyPath API currently doesn't allow us to initialize a new KeyPath from a string, but it does support dictionary "parsing".
The idea here is to build a dictionary that will describe the struct using the mirroring API, then iterate over the key to build the KeyPath array.
Swift 4.2 playground:
protocol KeyPathListable {
// require empty init as the implementation use the mirroring API, which require
// to be used on an instance. So we need to be able to create a new instance of the
// type.
init()
var _keyPathReadableFormat: [String: Any] { get }
static var allKeyPaths: [KeyPath<Foo, Any?>] { get }
}
extension KeyPathListable {
var _keyPathReadableFormat: [String: Any] {
let mirror = Mirror(reflecting: self)
var description: [String: Any] = [:]
for case let (label?, value) in mirror.children {
description[label] = value
}
return description
}
static var allKeyPaths: [KeyPath<Self, Any?>] {
var keyPaths: [KeyPath<Self, Any?>] = []
let instance = Self()
for (key, _) in instance._keyPathReadableFormat {
keyPaths.append(\Self._keyPathReadableFormat[key])
}
return keyPaths
}
}
struct Foo: KeyPathListable {
var x: Int
var y: Int
}
extension Foo {
// Custom init inside an extension to keep auto generated `init(x:, y:)`
init() {
x = 0
y = 0
}
}
let xKey = Foo.allKeyPaths[0]
let yKey = Foo.allKeyPaths[1]
var foo = Foo(x: 10, y: 20)
let x = foo[keyPath: xKey]!
let y = foo[keyPath: yKey]!
print(x)
print(y)
Note that the printed output is not always in the same order (probably because of the mirroring API, but not so sure about that).
After modifying rraphael's answer I asked about this on the Swift forums.
It is possible, discussion here:
Getting KeyPaths to members automatically using Mirror
Also, the Swift for TensorFlow team has this already built in to Swift for TensorFlow, which may make its way to pure swift:
Dynamic property iteration using key paths
I propose my solution. It has the advantage of dealing correctly with #Published values when using the Combine framework.
For the sake of clarity, it is a simplified version of what I have really. In the full version, I pass some options to the Mirror.allKeyPaths() function to change behaviour ( To enumerate structs and/or classes properties in sub-dictionaries for example ).
The first Mirror extension propose some functions to simplify properties enumeration.
The second extension implements the keyPaths dictionaries creation, replacing
#Published properties by correct name and value
The last part is the KeyPathIterable protocol, that add enumeration
capability to associated object
swift
// MARK: - Convenience extensions
extension String {
/// Returns string without first character
var byRemovingFirstCharacter: String {
guard count > 1 else { return "" }
return String(suffix(count-1))
}
}
// MARK: - Mirror convenience extension
extension Mirror {
/// Iterates through all children
static func forEachProperty(of object: Any, doClosure: (String, Any)->Void) {
for (property, value) in Mirror(reflecting: object).children where property != nil {
doClosure(property!, value)
}
}
/// Executes closure if property named 'property' is found
///
/// Returns true if property was found
#discardableResult static func withProperty(_ property: String, of object: Any, doClosure: (String, Any)->Void) -> Bool {
for (property, value) in Mirror(reflecting: object).children where property == property {
doClosure(property!, value)
return true
}
return false
}
/// Utility function to determine if a value is marked #Published
static func isValuePublished(_ value: Any) -> Bool {
let valueTypeAsString = String(describing: type(of: value))
let prefix = valueTypeAsString.prefix { $0 != "<" }
return prefix == "Published"
}
}
// MARK: - Mirror extension to return any object properties as [Property, Value] dictionary
extension Mirror {
/// Returns objects properties as a dictionary [property: value]
static func allKeyPaths(for object: Any) -> [String: Any] {
var out = [String: Any]()
Mirror.forEachProperty(of: object) { property, value in
// If value is of type Published<Some>, we transform to 'regular' property label and value
if Self.isValuePublished(value) {
Mirror.withProperty("value", of: value) { _, subValue in
out[property.byRemovingFirstCharacter] = subValue
}
} else {
out[property] = value
}
}
return out
}
}
// MARK: - KeyPathIterable protocol
protocol KeyPathIterable {
}
extension KeyPathIterable {
/// Returns all object properties
var allKeyPaths: [String: Any] {
return Mirror.allKeyPaths(for: self)
}
}

Swift override all setters and getters of a subclass

I would like to override a setter/getter one time for but for all the properties for a class in swift
This my class. I want to call Realm each time I am adding a new value
class House : Object
{
var a:String
{
set {
do {
let realm = try Realm()
try realm.write {
a = newValue
}
}
catch {
}
}
}
var b:String
{
set {
do {
let realm = try Realm()
try realm.write {
b = newValue
}
}
catch {
}
}
}
}
There is no way in Swift how you can overwrite setters for all properties at once.
What you could generally do though is use:
overwritten setters per property
abstract computed properties wrapping low-level properties
intercept getters and setters by KVC accessor methods (e.g. is<Key>, get<Key>, …) and rely only on untyped dynamic KVC-based access via valueForKey(Path):, if you want to apply the decorated behavior (which you might want to avoid for this reason)
But Realm is using custom getters and setters under the hood, which are dynamically overwritten in an dynamically inserted intermediate class at runtime and relies on the presence of those. So the only approach, which is really feasible is having dynamic stored properties declared and adding for each of those an extra property, based on those.
var storedPropertyA: String = ""
var computedPropertyA: String {
get {
// add your extra behavior here
return storedPropertyA
}
set {
// add your extra behavior here
self.storedPropertyA = newValue
}
}
Beside that there is an alternative way of using the decorator pattern and decorate your whole object with extra behavior. In Swift, you could have your object and your decorator implement a common protocol, which defines your properties.
protocol HousingProperties {
var a: String { get set }
}
class House: HousingProperties {
var a: String = ""
}
class HouseDecorator: HousingProperties {
internal var house: House
init(house: House) { self.house = house }
var a: String {
// add your extra behavior here
self.house.a = a
}
}
Still I would NOT recommend to intercept property setters and getters for the purpose you intend here. Instead I'd advise to structure your application's architecture in a way, that allows you to be aware whether there is a write transaction or not and let the responsibility of making a write transaction in the hands of the code, which tries to modify objects.
Let me explain why:
Realm is using a multiversion concurrency control algorithm to manage persisted data and achieve thread-safety. This makes sure that different threads can read data at any point in time without having to read-lock and trying to synchronize these. Instead when a write is happening, all accessors are notified that there is new data and try to move on to the newest transaction. Until that has happened, all versions between the oldest data version, which is still used by a thread and the one written have to be retained. They can be first released when all threads advanced their commit pointers. If you do a lot of small transactions, you risk that your file size will blew up to unnecessary high values. For that reason, we recommend to batch write transactions to large changesets.
There is one hack to kind of attain what the poster is looking for, however possibly not advisable... Anyway; you can can create your own assignment operators that does whatever you want to do in realm prior to assigning the values
class MyType {
var myInt : Int = 0
var myString : String = ""
init(int: Int, string: String) {
myInt = int
myString = string
}
}
infix operator === {}
func ===<T>(lhs: T, rhs: T) -> T? {
Realm() // replace with whatever Realm()-specific stuff you want to do
return rhs
}
protocol MyAddableTypes {
func + (lhs: Self, rhs: Self) -> Self
}
extension String : MyAddableTypes {}
extension Int : MyAddableTypes {}
infix operator +== {} // ... -== similarily
func +==<T: MyAddableTypes>(lhs: T, rhs: T) -> T? {
Realm() // replace with whatever Realm()-specific stuff you want to do
return lhs+rhs
}
func Realm() {
// ...
print("Called realm")
}
var a = MyType(int: 1, string: "foo")
a.myString === "bar" // calls Realm(). After operation: a.myString = "bar"
a.myInt +== 1 // calls Realm(). After operation: a.myInt = 2
I thought I'd also mention that if you only want to do "Realm stuff" when a value is set (from your example: prior to setting a value, specifically), then the willSet method, used with stored properties, doesn't need to look so messy (nested closures), and personally, I would prefer this method
func Realm() {
print("Called realm")
}
class MyType {
// This isn't so messy, is it?
var myInt : Int = 0 { willSet { priorToSetValue(newValue) } }
var myString : String = "" { willSet { priorToSetValue(newValue) } }
var myDouble : Double = 0.0 { willSet { priorToSetValue(newValue) } }
private func priorToSetValue<T> (myVar: T) {
// replace with whatever Realm()-specific stuff you want to do,
// possibly including doing something with your new value
Realm()
}
init(int: Int, double: Double, string: String) {
myInt = int
myDouble = double
myString = string
}
}
var a = MyType(int: 1, double: 1.0, string: "foo")
a.myString = "bar"
print(a.myString) // calls Realm(). After operation: a.myString = "bar"
a.myInt += 1 // calls Realm(). After operation: a.myInt = 2