rubymotion-community / BubbleWrap

Cocoa wrappers and helpers for RubyMotion (Ruby for iOS and OS X) - Making Cocoa APIs more Ruby like, one API at a time. Fork away and send your pull requests
Other
1.18k stars 208 forks source link

Add Archive functionality to BW::Persistence #389

Open dv opened 10 years ago

dv commented 10 years ago

This PR adds the Archive module to Persistence. It simplifies storing objects that need NSKeyArchiver. The class of the object still needs to implement the NSCoding methods, but other than that you can simply do:

BW::Persistence::Archive[:my_object] = an_object
# And retrieve...
an_object = BW::Persistence::Archive[:my_object]

Instead of doing the NSKeyArchiver dance. This also works with Arrays and Hashes of objects, which are converted to Arrays and Hashes of archived objects respectively:

BW::Persistence::Archive[:my_object] = [object1, object2, 123, object4]
BW::Persistence::Archive[:some_hash] = {first: object1, second: object2, third: [object4, object5]}

This will recursively use NSKeyArchiver to convert all objects to NSUserDefaults-compatible types (i.e. it'll keep Strings and Numbers as Strings and Numbers, but convert any other object to NSData if they do NSCoding).

It's compatible with normal BW::Persistence (or indeed NSUserDefaults) usage. For example after the previous two lines, you could do this to retrieve the stored number:

BW::Persistence[:my_object][2] == 123 # true

The reason this cannot (probably) be implemented by default in BW::Persistence is that we don't know beforehand if the user stored NSData or an object that is archived to NSData, so we don't know whether to unarchive it or not.

We could make the convention that any NSData in BW::Persistence should be unarchived, and that you can't retrieve NSData from BW::Persistence without specifying you don't want it to be unarchived. We could also try to unarchive all NSData and only when NSKeyArchiver throws an exception return the raw NSData.

This merits a discussion.

clayallsopp commented 10 years ago

This is definitely cool, thanks for submitting the PR! I'll leave it open to @markrickert and @colinta's thoughts

The reason this cannot (probably) be implemented by default in BW::Persistence is that we don't know beforehand if the user stored NSData or an object that is archived to NSData, so we don't know whether to unarchive it or not.

One solution to this could be key-mangling:

BW::Persistence[:my_object] = my_object
# internally Persistence checks if my_object can be serialized (is NSCoding compliant etc)
# if so, save the key as :__archive__my_object

my_object = BW::Persistence[:my_object]
# check if :__archive__my_object exists and return, serializing if appropriate

Not sure if that's what we actually want, but it seems possible.

markrickert commented 9 years ago

@dv Could you add some documentation for this? Sorry its taken so long for me to get to this, but its definitely a cool feature!