Custom setter/willSet for Realm Object - swift

Whenever I set a property of a Realm object I want to trigger the change of an other object that represents the object on my remote backend.
I was wondering if this is still the best practice recommended:
https://github.com/realm/realm-cocoa/issues/870#issuecomment-54543539
What I was trying to do, but doesn't work because it interferes with Realm:
dynamic var name: String = "" {
willSet(newValue) {
self.name = newValue
self.widgetRemote?.name = newValue
}
}

Yes, the workaround suggested in realm/realm-cocoa#870 is still the best way to achieve this. For your case you'd want to do something like:
#objc private dynamic var backingName = ""
var name : String {
get {
return backingName
}
set(newValue) {
backingName = newValue
widgetRemote?.name = newValue
}
}
override class func ignoredProperties() -> [String] {
return ["name"]
}

bdash's version in objc:
+(NSArray<NSString *> *)ignoredProperties
{
return #[ #"name" ];
}
see the answer bdash's swiftly provided to obtain more context on backing store exampt from persistence into realm store

Related

Exposing dictionary in Swift property wrappers

I have an internal dictionary that I don't want to expose to the user. Instead, I expose only certain values using properties, like this:
public var artist: String? {
get {
return items["artist"]
}
set {
items["artist"] = newValue
}
}
//...so on for another 20 or so items
As you can imagine, this ends up getting repeated quite a lot. I was thinking that property wrappers would be a nice way to clean this up - however, it's not possible to pass items directly to the wrapper, since property wrappers are created before init (so self would not be accessible).
Is there a way around this, or is this just one of the limitations of propertyWrappers?
You could build a generic solution. I did one, but you can probably improve it:
class PropertyWrapper {
private var items: [String: Any] = ["artist": "some dude"]
enum Key: String {
case artist
}
func getItem<T: Any>(key: Key) -> T {
guard let item = items[key.rawValue] as? T else {
preconditionFailure("wrong type asked for")
}
return item
}
func setItem(value: Any, key: Key) {
items[key.rawValue] = value
}
}
class GetValueClass {
func getValue() {
let wrapper = PropertyWrapper()
let value: String = wrapper.getItem(key: .artist)
}
}
class SetValueClass {
func setValue() {
let wrapper = PropertyWrapper()
wrapper.setItem(value: "some", key: .artist)
}
}

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

Read once and then set to nil

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
}
}
}

Mirroring Not Picking Up Base Class on Swift 3

I am building a function that will take an instance of a class object and convert it to an XML request to be sent to a web service. To accomplish this, I am using mirroring to iterate through the key/value pairs in the class. In my testing, I see it is working great, with one major problem, none of the inherited class parameters are coming across. For example, in the code below, the loop is executed three times for "descriptionText, modelNumber and serialNumber, name and uuid are never collected. Is there a way for me to use mirroring and pick up all the parameters of the base class, as well as the widget? Also, if there is a better way to do this, I am all ears.
import UIKit
class BaseObject: NSObject {
var name = String()
var uuid = String()
}
class Widget: BaseObject {
var descriptionText = String()
var modelNumber = String()
var serialNumber = String()
}
var widget1 = Widget()
widget1.name = "Generic Widget"
widget1.uuid = "A guid"
widget1.descriptionText = "Class A Extra Larget Widget"
widget1.modelNumber = "1234"
widget1.serialNumber = "4321"
let widgetMirror = Mirror(reflecting: widget1)
for attr in widgetMirror.children {
print(attr.label!)
}
You need to use the superclassMirror: Mirror? property for that. For instance:
for attr in widgetMirror.superclassMirror!.children {
print(attr.label!)
}
prints the expected results:
name
uuid
Update. If you keep running into this, add this Mirror extension to your toolkit:
extension Mirror {
var allChildren: [Mirror.Child] {
var allChildren: [Mirror.Child] = []
var mirror: Mirror! = self
repeat {
allChildren.append(contentsOf: mirror.children)
mirror = mirror.superclassMirror
} while mirror != nil
return allChildren
}
}
Usage:
for attr in widgetMirror.allChildren {
print(attr.label!)
}
A partial answer was already posted, but here is a way to wrap it all up.
var mirror: Mirror? = Mirror(reflecting: widget1)
repeat {
for (index, child) in mirror!.children.enumerated() {
print (child.label!)
}
mirror = mirror?.superclassMirror
} while mirror != nil
I thought about a bit more. I think this is more Swifty.
extension Mirror {
var posterity: Children {
if let superclassMirror = superclassMirror {
return Children([children, superclassMirror.posterity].joined())
} else {
return children
}
}
}
let widgetMirror = Mirror(reflecting: widget1)
for child in widgetMirror.posterity {
print(child.label!)
}

How can I set a string variable and make it always lowercase?

I want to set a string variable and want to keep it always lowercase.
This is my code :
var alwaysLowercaseString : String? {
didSet{
alwaysLowercaseString = alwaysLowerCaseString!.lowercaseString
}
}
But when I use it, it goes into a infinite loop. How can I solve this problem?
I stand corrected, this is the correct approach. LeoDabus deserves the credit for this answer:
var alwaysLowercaseString : String? {
didSet{
alwaysLowercaseString = alwaysLowercaseString?.lowercaseString
print(alwaysLowercaseString)
}
}
var alwaysLowercaseString : String? {
didSet{
if alwaysLowercaseString != alwaysLowerCaseString!.lowercaseString {
alwaysLowercaseString = alwaysLowerCaseString!.lowercaseString
}
}
}
This checks so if the lowercase string is already lowercase it won't change the value of alwaysLowercaseString again so you won't call didSet infinitely. It will break after alwaysLowercaseString is set to lowercase.
Since Swift 5.1 there's a possibility to use property wrappers. Roughly speaking, this mechanics allows us to modify the value each time it is set
#propertyWrapper struct Lowercased {
var wrappedValue: String {
didSet { wrappedValue = wrappedValue.lowercased() } // here the magic happens
}
init(wrappedValue: String) {
self.wrappedValue = wrappedValue.lowercased() // we have to do it manually here because in init property observers are not triggered
}
}
final class Test {
#Lowercased var cantMakeMeUpperCase = ""
}
let test = Test()
test.cantMakeMeUpperCase = "CAN I?"
print(test.cantMakeMeUpperCase) // prints "can i?"