I'd like to able to get a unique ID for an object so that I can later test another object against it, without having to keep the first object. Say I have an NSArray of NSDictionaries that describes some sort of playlist (not the best way to store data but for arguments sake). Its too big to store, and the user may have many of them; everytime the user uses the application I just download it again. I want to be able to offer the user the ability to continue the playlist from his last location but only if the playlist is exactly the same (say its some sort of feed that updates regularly, but always has the same count). Is there some sort of quick way to ID that object into a small'fingerprint' object, and then test the new playlists fingerprint against it? Obviously it doesn't have to be perfect (otherwise it would be the whole object), just something unique enough to test 'likely' equality. (Note: I'd prefer a solution that worked for any NSObject-not just an NSArray of NSDictionaries).
My naive approach was to just concatenate the first the first three letters of all of the NSStrings in each NSDictionary - that seems silly.
Related
I have an app that is using Firebase quite extensively to store data that contains relationships. I want to make sure I am using Firebase as safely as possible in offline mode. The safety concern I have can be demonstrated in the following example:
Assume I have a Zoo model where each individual zoo is stored in Firebase as a subnode of "/zoos".
I have an Animal model where each individual animal is stored in Firebase as a subnode of "/animals".
A Zoo can have Animals which are stored in an ordered list. Specifically, the Zoo model contains an Animal array e.g. [Animal]. This list of Animals is stored in Firebase as a set of position-reference pairs at "/zoos/myZoo/animals" which will contain nodes like:
{0: "animals/fidoTheDog"},
{1: "animals/jillTheCat"}
When I add a new Animal to a Zoo, I need to know how many animals are currently in that zoo so I can add the new animal in the right position like:
{2: "animals/jakeTheSnake"}
If I am offline and happen to read the location "zoos/myZoo/animals" to get the list of animals so I can add in the right position, I want to make sure I have accurate data. I know that if someone else wrote to that position while I am offline and added another animal in position 2, I will get stale data and when I add an animal in position 2, I will overwrite his entry at "zoos/myZoo/animals/2" when I again go online. So that is an issue.
But, if I know I will be the only one writing to that location, can I be relatively sure that Firebase will hold the crucial data at "zoos/myZoo/animals" for me since I am using isPersistenceEnabled = true? In other words, will Firebase just keep that data in cache as long as I have recently written to that location or recently read from that location?
Or do I explicitly need to specify "keepSynced(true)" on that location? This gets to the core general version of the question - How does Firebase choose what to store in its cache with isPersistenceEnabled = true? Especially if I have not specifically set keepSynced(true) on any particular locations. Will Firebase just prioritize recently read data and then when the 10mb limit is hit, discard the old stuff first? Does it matter if I wrote the data to that location a long time ago but consistently read from that location? Will it still maintain that location in the cache because it was recently read? Will it ever discard data before hitting the 10mb limit?
I'm a little bit of a newbie so thank you for your patience with me!
-------------- FOLLOW UP QUESTIONS --------------
A couple follow up questions.
I think the approach suggested in the blog (given by Frank in comments) of using childByAutoID sounds good. So if I am saving a zoo with many animals (in order) then it sounds like I would loop through the animals and use childByAutoID to create a new key for each animal whose value will be the reference to the location of the animal object. Can I be sure that the keys that I create in rapid succession (looping will probably be very fast) will ultimately sort correctly when ordered lexicographically? I’m looking at this blog post and assuming that is the case. https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html
Suppose I am doing something more complicated like inserting an animal at the beginning of the list in position zero. Then before doing the operation, I would sync down the list of animals in the zoo as suggested in the blog post you sent. https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html. If the user is offline, I obviously can’t be sure that I will have the freshest copy. But suppose I am ok with that because users will only be working with their own data and only on their own device. In that case, does it help to use keepSynced(true) on the path to the zoo? Or since the amount of data the user is working with is well, well under 10mb (the whole database right now is 300k for 10ish active users), can I just assume the cache will store the data in the zoo path (whether keepSynced or not) because we never flirt with the 10mb limit in any case?
Thank you!
I hope this isn't an inappropriate post, but I wanted to make sure my first steps implementing parse as my backend are in the right direction to save some time. I'm new to both iOS programming and the parse sdk, so please bear with me!
In my app, users are able to create various polygon shape overlays on a Google Maps mapView, stored as a GMSMutablePath, which is basically a list of coordinates. Users will have at least one group of paths, each with at least one path. There will also be some information stored with each group, stored as strings or numbers. This information is specific to a single group of paths.
I'm trying to figure out the best way to store this data. My first basic question is 1) Can I store the GMSMutablePath as a whole in the Object data type? Or does the Object data type refer to a class that is created through parse? This link (https://www.parse.com/questions/what-is-data-type-of-object-in-data-browser) is the 'best' explanation I found of the Object data type, and it isn't very clear to me.
My gut instinct is no, I can't store the GMSMutablePath object, and that Object refers to a Parse object. Which leads me to 2) How should I store this data, then? I can get the individual lat/long values of the coordinates that make up each path, and I can store those as numbers, and use the numbers to recreate the paths elsewhere. None of the paths should use too many coordinates, and there shouldn't be too many paths in each group.
Playing around a little bit in the data browser, I see that I can store arrays, but I'm not sure how those are formatted, as I'd need an array (of groups) of arrays (of paths) of arrays (of lat/long values). A little bit of googling tells me it can be done, but doesn't show me how. Can any datatype be stored in any array, or is a datatype specified? I'm used to C++ programming, so I'm used to an array containing a single type of element. What I'm thinking is that I'd need an array of objects, which would be the groups of paths. Each one of those objects would have the string/number information associated with the group, as well as an array for the paths within the group. For each one of those paths, it would have to be either an array or an object. Since for the path I just need the coordinate lat/long values, I think that I can get away with an each path being an array of numbers, and I can write my program to use one array, with odd indexes being lat / even indexes being long values. That all being said, I'm not sure how to create all of that. I'm not looking for somebody to write my implementation for me, but all of the examples I can find are much more simple... if anybody could point me in the right direction to do this, or has a better idea of how to do it, I'd love some pointers.
Each user is going to have their own groups, but that data is going to be shared with others at some point. The data will be associated with the user it belongs to. With that in mind, my last question is 3) Should I store all of this information specific to a user and their groups on the User class, or make it all a separate class entirely? My guess it that I should add an Object to the User class, and store the groups within that Object. I just want to make sure I have that right, with future scalability in mind. Like, when I pull the group data, am I going to have to pull the entire User data from another user, and if so, is that going to slow things down significantly? I'm thinking that I do have to send entire user data, but I don't know if that poses any security risks. Would it be best to have a separate class for the groups, and store the user id associated with the groups? If I do this, should I also store the groups as an object on the User class?
Sorry for the wall of text, but thank you for any guidance you can provide!
If you need any clarification, let me know.
Thanks,
Jake
Creating a class to hold all the objects turned out to be unnecessary. It only had a few extra details that were just as convenient to add to the user object, and then have an array of objects on the user.
Some main things to note that I learned are: use addObject to add to an array, rather than setObject to add a single object to a PFObject/User.
Parse fetching/saving happens in background threads, so if you're loading the data to do something specific with it, make sure the code using the data occurs inside a block using the [PFObject fetchInBackgroundWithBlock] method.
Also, as changes are made to the structure of your data on a parse user/object, make sure you sign out of the current user and create a new one on your app, or you may run into lots of undefined behaviour that could crash your app.
My question :
I need to know if what i'm doing is the best way, and if it's not, what is?
The situation :
I have "Contacts" objects in an array. These contacts must be ordered alphabetically and can have multiple phone numbers. I'm splitting that array into 27 arrays of contacts where each of them reprensents a letter of the alphabet. So i have all my "A" contacts, then "B" and so on.
Also, during the "splitting", I also add a reference of each contact in a dictionary, where the object is the contact, and the key is his phone number.
Because one contact can have X phone numbers, there can be X times the same contact in X different entries in the dictionary. I need that so i can find any contact with any number.
All of the above works like a charm.
Now I need to compare all those numbers from my online database (note: i'm using parse), to see if some of these contacts are already users or not. If they are, they need to be put in a specific section of my tableview. (my tableview is just all the contacts, separated in letter sections, + one "user" section). And the contacts can not appear in the user section AND the letter section. If a contact is a user, he must be separated.
What i'm asking vs What i'm doing :
Right now, i'm just re-looping every array and comparing each element to all the users i've found online. This is a lot of looping and looks like a waste of time and resources.
What i would like to do : Somehow cleaning my arrays of the users i've found, considering i have the reference of the contact object in my dictionary.
TL;DR:
My arrays :
users in the first section, then contacts alphabtically
[[user1, user2, user3, ...],[a1,a2,a3,...],[b1,b2,...],...]
My dictionary :
a1 - phone1
a1 - phone2
a1 - phone3
a2 - phone1
a3 - phone1
...
The ultimate question :
I can very easily find the contact object (since i have his number from my online db). If i interact with the a1 from the dictionary, will it also change the a1 in the array of arrays?
More specifically, can i somehow REMOVE IT from the array considering I don't know which one he is in?
I also add a reference of each contact in a dictionary, where the object is the contact, and the key is his phone number.
You need to be very careful with this approach. It is likely to have collisions. While cell phone numbers are often unique, sometimes they're shared. Home and work numbers are often shared. Phone numbers get reassigned, so your database can wind up with duplicates that way, too. And sometimes people just enter mistaken data. You have to make sure your system behaves reasonably and consistently in those cases. Many behaviors are fine, but "pick one at random" is generally not.
You should think carefully here about what is your model and what is your presentation. One data structure should be the single source of truth. Usually that's going to be your big list of contacts. That has nothing at all to do with how it's displayed. We call this the model. Often it's kept track of as an NSSet since order doesn't matter.
Above that you should have a "view model" that deals with grouping and sorting issues. It is not "truth." You should be willing to throw it away anytime the underlying data changes extensively. Its data structures should point to the underlying model, and should be stored in a way that exactly matches what the table view wants. Keeping the model and the view model separate is one of the best ways to keep your complexity under control. Then you know that there is exactly one place that data can change (the model), and everything else just reacts to that.
Regarding your partitioning problem: so you have a list of contacts and you want to separate them into two groups based on whether any of their phone numbers appear in another list. If your total list is only a few dozen entries long, frankly it doesn't matter how you do this. Even O(n^2) is fine for small enough n. Focus on making it simple and reliable first, then profile with Instruments to see where the real bottlenecks are.
That said, usually the fastest way to determine set intersection is to sort both sets and walk through them both at the same time. So you'd create a "contacts" array of "phone number + contact pointer" and a "users" array of just phone numbers. Sort them both by phone number. Walk over them, comparing the current element of each list, and then incrementing the index of the smaller one. If no match, put the contact in one list. If a match, put it in the other.
But I'd probably just stick all the phone numbers in a set and use member: to look them up. It's just usually easier.
I've had a problem for a while and I have hacked together a solution but I am revisiting it in the hopes of finding a real solution. Unfortunately that is not happening. In Core Data I've got a bunch of RSS articles. The user can subscribe to individual channels within a single feed. The problem is that some feed providers post the exact same article in multiple channels of the same feed. So the user ends up getting 2+ versions of the same article. I want to keep all articles in case the user unsubscribes from a channel that contains one copy but stays subscribed to another channel with a duplicate, but I only want to show a single article in the list of available articles.
To identify duplicates, I create a hash value of the article text content and store it as a property on the Article entity in Core Data (text_hash). My original thinking was that I would be able to craft a fetch request that could get the articles based on a unique match on this property, something like an SQL query. That turns out not to be the case (I was just learning Core Data at the time).
So to hack up a solution, I fetch all the articles, I make an empty set, i enumerate the fetch results, checking if the hash is in the set. If it is, I ignore it, if it isn't, i add it to the set and I add the article id to an array. When I'm finished, I create a predicate based on the article ids and do another fetch.
This seems really wasteful and clumsy, not only am i fetching twice and enumerating the results, since the final predicate is based on the individual article ids, I have to re-run it every time I add a new article.
It works for now but I am going to work on a new version of this app and I would like to make this better if at all possible. Any help is appreciated, thanks!
You could use propertiesToGroupBy like so:
NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:#"Article"];
fr.propertiesToGroupBy = #[#"text_hash"];
fr.resultType = NSDictionaryResultType;
NSArray *articles = [ctx executeFetchRequest:fr error:nil];
It is pretty common for a web application to display a list of items and for each item in the list to indicate to the current user whether they have already viewed the associated item.
An approach that I have taken in the past is to store HasViewed objects that contain the Id of a viewed item/object and the Id of the User who has viewed that item/object.
When it comes time to display a list of items this requires querying the database for the items, and separately querying the database for the HasViewed objects, and then combining the results of these queries into a set of objects constructed solely for the purpose of displaying them in the view.
Each e.g li then uses the e.g. has_viewed property of the objects constructed above.
I think it is time to find a better approach and would like to know what approaches you would recommend.
i wanna to know whether there is better idea also.
Right now my solution is putting the state in the redis and cached the view with fragment cache.