Pass a copy of an object in storage without the reference to avoid users from modifying the object in storage - onflow-cadence

pub fun getAddresses(): {Address: Bool} {
return Contract.account.borrow<&{Address: Bool}>(from: storage/dict) as! {Address: Bool}
}
In other words, I don’t want to pass back to the caller the reference to the dictionary because then they will be able to modify the actual dictionary object in storage. I just want a copy of the dictionary object returned, but don’t want to create a copy through looping over the address dictionary as that will be computationally expensive… Is there any way to remove the reference?

Have you consider storing a struct in your storage that has this as a field? Then you can get a reference to the struct and then send this field back?

Related

Adding a deleted or invalidated object to a Realm is not permitted

I am trying to delete(truncate table) object and than adding it again, but getting this exception at runtime:
Adding a deleted or invalidated object to a Realm is not permitted
My code:
let realm = try! Realm()
let objFolder = realm.objects(FolderColor.self)
do{
try realm.write {
realm.delete(objFolder)
for obj in arrFolderColors {
realm.add(obj)
}
}
}
catch{}
I like the other answer but I think what's going on here is you have a class var
#objc dynamic var folderColorResults = Results<FolderColor>
and at some point you've populated that var with some FolderColor objects
self.folderColorResults = realm.objects(FolderColor.self).filter("color == 'blue'")
So then, when you call the code in the question, it's deleting all of the FolderColor objects from Realm - when that happens, the folderColorResults results var is also getting updated (all objects removed).
Therefore there are no objects to write back out to disk.
Remember that Realm is a live database and Results objects are always keep in sync with the actual data; change an object on one place, it changes it everywhere that object is being used.
A suggested fix is to cast the folderColorResults to an Array.
let myArray = Array(self.folderColorResults)
which disconnects those objects from Realm and they will not be updated.
Of course, I could be totally wrong on this assumption so I can update further if more information is provided.
Realm objects are simply pointers to their data in the Realm database. When you call realm.delete, you completely delete the contents from memory and disk. The Realm object itself is still in memory, but you can’t call any properties or try and re-add it.
There’s a object.invalidated property you can use to check if an object has been deleted before you try and add it to Realm to avoid accidentally triggering that exception.
I’d recommend you rethink your logic to not need to call ‘realm.delete’. If it’s in an array, you can just remove it from the array but keep it in the database.

is it possible to retain data within a model class

I'm new to and starting to look at swift.
is it possible to store and retrieve data in swift without having to use NSObject?
here I what I'm trying to achieve. I have a set of 4 ViewControllers.
On the first ViewController I want to record a name.
In my last ViewController I want to read that name.
I tried to store it in a simple model as shown:
class infoModel
{
var m_name : String
init(_name: String) {
self.m_name = _name
}
func getName() -> String {
return m_name
}
}
when I call getName from my fourth View its null?
I know its possible to pass data in segue or use NSUserDefaults, but I'm curious if its possible for the model object to retain the value?
Thank you in advance for your time
I think this is general programming rule for objected oriented languages.
As long as you have reference to the same object, you will have the object with the same data. And its up to you how you pass this data between other objects; using delegates or just assigning some variable, etc.
Also there are ways how to save data which allows you to save data somewhere else and then retrieve them. To saving small amount of data you can use in Swift UserDefaults, but for bigger amount of data you should work with some database (e.g. Realm, CoreData).

Array pass by value by default & thread-safety

Say I have a class which has an Array of object Photo:
class PhotoManager {
fileprivate var _photos: [Photo] = []
var photos: [Photo] {
return _photos
}
}
I read one article which says the following:
By default in Swift class instances are passed by reference and
structs passed by value. Swift’s built-in data types like Array and
Dictionary, are implemented as structs.
Meaning that the above getter returns a copy of [Photo] array.
Then, that same article tries to make the getter thread-safe by refactoring the code to:
fileprivate let concurrentPhotoQueue = DispatchQueue(label: "com.raywenderlich.GooglyPuff.photoQueue",
attributes: .concurrent)
fileprivate var _photos: [Photo] = []
var photos: [Photo] {
var photosCopy: [Photo]!
concurrentPhotoQueue.sync {
photosCopy = self._photos
}
return photosCopy
}
The above code explictly make a copy of self._photos in getter.
My questions are:
If by default swift already return an copy (pass by value) like the article said in the first place, why the article copy again to photosCopy to make it thread-safe? I feel myself do not fully understand these two parts mentioned in that article.
Does Swift3 really pass by value by default for Array instance like the article says?
Could someone please clarify it for me? Thanks!
I'll address your questions in reverse:
Does Swift3 really pass by value by default for Array instance like the article says?
Simple Answer: Yes
But I'm guessing that is not what your concern is when asking "Does Swift3 really pass by value". Swift behaves as if the array is copied in its entirety but behind the scenes it optimises the operation and the whole array is not copied until, and if, it needs to be. Swift uses an optimisation known as copy-on-write (COW).
However for the Swift programmer how the copy is done is not so important as the semantics of the operation - which is that after an assignment/copy the two arrays are independent and mutating one does not effect the other.
If by default swift already return an copy (pass by value) like the article said in the first place, why the article copy again to photosCopy to make it thread-safe? I feel myself do not fully understand these two parts mentioned in that article.
What this code is doing is insuring that the copy is done in a thread-safe way.
An array is not a trivial value, it is implemented as multi-field struct and some of those fields reference other structs and/or objects - this is needed to support an arrays ability to grow in size, etc.
In a multi-threaded system one thread could try to copy the array while another thread is trying to change the array. If these are allowed to happen at the same time then things easily can go wrong, e.g. the array could change while the copy is in progress, resulting in an invalid copy - part old value, part new value.
Swift per se is not thread safe; and in particular it will not prevent an array from being changed while a copy is being performed. The code you have addresses this by using a GCD queue so that during any alteration to the array by one thread all other writes or reads to the array in any other thread are blocked until the alteration is complete.
You might also be concerned that their are multiple copies going on here, self._photos to photoCopy, then photoCopy to the return value. While semantically this is what happens in practice there will probably only be one complex copy (and that will be thread safe) as the Swift system will optimise.
HTH
1) In code example what you provided will be returned copy of _photos.
As wrote in article:
The getter for this property is termed a read method as it’s reading
the mutable array. The caller gets a copy of the array and is protected
against mutating the original array inappropriately.
that's mean what you can access to _photos from outside of class, but you can't change them from there. Values of photos could be changed only inside class what make this array protected from it accidental changing.
2)Yes, Array is a value-type struct and it will be passed by value. You can easily check it in Playground
let arrayA = [1, 2, 3]
var arrayB = arrayA
arrayB[1] = 4 //change second value of arrayB
print(arrayA) //but arrayA didn't change
UPD #1
In article they have method func addPhoto(_ photo: Photo) what add new photo to _photos array what makes access to this property not thread-safe. That's mean what value of _photos could be changed on few thread in same time what will lead to issues.
They fixed it by writing photos on concurrentQueue with .barrier what make it thread-safely, _photos array will changed once per time
func addPhoto(_ photo: Photo) {
concurrentPhotoQueue.async(flags: .barrier) { // 1
self._photos.append(photo) // 2
DispatchQueue.main.async { // 3
self.postContentAddedNotification()
}
}
}
Now for ensure thread safety you need to read of _photos array on same queue. That's only reason why they refactored read method

Swift - Empty NSMutableDictionary or NSDictionary? Optional

Just curious, in Swift, is it more ideal to initialize an empty NSMutableDictionary variable, NSMutableDictionary = [:], and later re-assign its value to a new dictionary (coming from an API for example),
OR, is it better to declare an optional NSDictionary, NSDictionary? and assign it to a new dictionary?
So with Swift it would technically be best practice to use a Dictionary type. Like this for example:
var dict: Dictionary<String, Int>
If you need the dictionary as a whole to be able to be nil use an optional.
This depends on your needs, do you want it to be nil sometimes? is it nil sometimes?
If an array is always gonna have value, even if it's an empty value, I personally like to Initialize it right away, and not hassle with unwrapping everywhere.
Maybe if you had two arrays, one was normal array, and the second one was a searched result. You might wanna check if searched result is nil first, if it is, show the array1, if it isn't show it instead.
And this is implying you only search "sometimes", thus that array is only sometimes used - so you might as well have that deallocated when not in use, if you aren't using it most of the time.
EDIT: I've been using arrays in my example, but same applies for a dictionary in those situations.
EDIT: In Swift It's best to avoid 'NS' classes, sometimes you have to use them, sure. But Swift's Dictionary does the job.
Example:
var sometimesUselessDict: Dictionary<String, AnyObject>?
var alwaysUsedDictionary = Dictionary<String, AnyObject>()
Cheers
You should make it optional only if you need to be able to distinguish a dictionary that's empty from one that doesn't exist at all. For instance, if you're receiving data from a server, you might want to distinguish between a successful response that returned no data (empty dictionary) and a failed or invalid response (nil).
If that distinction isn't important, I would always go with a non-optional to avoid unnecessary unwrapping.

NSUserDefaults and Conditional Encoding of Custom Objects in an NSArray

I know there are a lot of posts out there concerning the problem of how to archive custom objects in an NSArray or NSMutableArray and save them in NSUserDefaults. Conforming to the NSCoding Protocol and saving to NSUserDefaults isn't problematic and I use NSUserDefaults quite a lot to store the user-submitted data in my app - it mostly contains objects representing a Person (let's call the NSObject subclass "Person") which can have multiple objects of the NSObject subclass "Property" stored in an NSMutableArray. Therefore, the data structure looks like this:
NSMutableArray "persons":
Person "aPerson":
NSMutableArray "properties":
Property "aProperty"
Property "anotherProperty"
Person "anotherPerson:
...
Archiving and restoring the information was not problematic at first, because both Person and Property conform to the NSCoding Protocol - but now a problem occured which I was not able to solve yet despite those thousands of google requests in the last couple days ;)
Some of the Property objects contain references to other Persons ("Participants", which are linked to the same property and are contained in an NSMutableArray).
When I store the whole data to NSUserDefaults using NSKeyedArchiver, I use
[aCoder encodeObject:participants forKey:#"participants"];
in the Property's "encodeWithCoder" method to archive the NSMutableArray "participants" which stores the references to other Person objects. But when I decode those Person objects, they are created new and separated from the Person objects that already exist somewhere else. The NSMutableArray "participants" only contains references, weak links to the Person objects and should therefore conditional encode its content, as one can do with other objects manually in "encodeWithCoder":
[aCoder encodeConditionalObject:anObject forKey:aKey];
When the NSMutableArray gets decoded, it should represent a list of references to already existing Person objects - not completely new ones! The test "aPerson==[[aDecoder decodeObjectForKey:#"participants"] objectAtIndex:0]" is currently returning NO although it had returned YES before the encoding/decoding process has taken place.
I hope my explanation is somehow understandable and you can help me with my problem :) In simple words: How can I conditional encode custom objects contained in an NSMutableArray?
Thank You !
If NSMutableArray would use encodeConditionalObject:forKey: for the objects it contains, it would just mean that those objects aren't encoded at all, if they're not encoded unconditionally somewhere else in your object graph. This wouldn't help you in this case (the array would just be empty).
The problem is that you cannot really encode references to objects in memory. An object reference is basically just a pointer to an address in memory. When you start your app the next time and create the very same object (whether by unarchiving or otherwise), it will almost definitely have a different address in memory. There is no way the unarchiver can 'magically' know, which existing object corresponds to the reference it has archived, because the memory address (the object's 'identity') loses all its meaning when you quit your app.
You have to use other means of identifying your objects, such as database row IDs, dictionary keys, etc. and establish the connection of the archived key and the existing object corresponding to that key manually.
I had an issue with this too. I have objects that have an array of weak links to other objects. I know all the objects linked to will be encoded, so I just want to make sure I can rebuild the links.
With a single weak link is it possible to use:
aCoder.encodeConditionalObject(thing, forKey: "Thing")
...and if that item has already been encoded from elsewhere, then a reference to that encoded item will be used.
But, what to do if you have an array full of 'conditional' items, where the array needs to be encoded unconditionally?
I ended up wrapping the items I want to link to.
class thingLink: NSObject, NSCoding
{
weak var thing: Thing?
init(_ thing: Thing) {
self.thing = thing
}
required init?(coder aDecoder: NSCoder) {
thing = aDecoder.decodeObject(forKey: "Thing") as? Thing
}
func encode(with aCoder: NSCoder) {
// We encode these conditionally as they must be used elsewhere
aCoder.encodeConditionalObject(thing, forKey: "Thing")
}
}
...then I store these in my array which I encode as usual.
aCoder.encode(things, forKey: "Things")
If I move to a database to store things, I think this will help there too, because I will need a separate table to store the links and maintain priority etc.