Comparing the attribute contents of two managed objects? - iphone

I am setting a managedObject up from data I am getting off the web, before I add this new object to the managedObjectContext I want to check if its all ready in the database. Is there a way to compare two managed objects in one hit, or do I have to compare each attribute individually to work out if they are identical or one contains a difference?
Simple Example:
Entity:Pet (Created but not inserted into database)
Attribute, Name: Brian
Attribute, Type: Cat
Attribute, Age: 12
Entity:Pet (Currently in database)
Attribute, Name: Brian
Attribute, Type: Cat
Attribute, Age: 7
In this example can I compare [Brian, Cat, 12] with [Brian, Cat, 7] or do I need to go through each attribute one by one to ascertain a full match?

Unique identifiers are often used to search for objects by only having to match the one field. As you note, matching on multiple fields could be annoying and inefficient, but it's perhaps not as bad as you think: you can construct an NSPredicate to quite easily match all the required fields on objects in Core Data.
Use of NSPredicate aside: suppose you just want to match one field. If you don't have a suitable unique identifier in the data as provided, you could derive one. The obvious way is to construct a hash code for everything you store, based on each field you want to match on. Then when you wish to check if an 'incoming' object is already in core data, compute the hash code for the new object, then just look for an object in core data with that same hash code. (Note: if you find an object that already exists with the same hash code, you might want to then compare all the fields to check that it really does represent the same object -- there's a tiny chance it might be a 'different' object, A.K.A. a hash collision).
A very naive hash code implementation for an object X would be something like:
hashcode(X) = hashcode(X.name) + hashcode(X.type) + hashcode(X.age)
To see a more realistic example of writing a hashcode function, see the accepted answer here.
By the way, I'm assuming that you don't want to load all your objects from core data into memory at once. If however that is acceptable (suppose you have quite a limited amount of items), an alternative is to implement isEqual and hash on your class, and then use regular foundation class methods like NSArray indexOfObject: (or, even better, NSDictionary objectForKey:) to locate objects of interest.

Related

Swift Ordered Set

Does Swift have an ordered set type? And if not, what are my options if I want to use one?
The standard library's Set is unordered, as is made clear in the documentation:
Arrays are ordered collections of values. Sets are unordered collections of unique values. Dictionaries are unordered collections of key-value associations.
However, many data structures suitable for implementing ordered sets (and dictionaries) are known, in particular balanced binary trees such as Red-Black trees.
As an example of this, c++'s stl has ordered sets and maps, and allows range queries on them using lower and upper bounds.
I know that a set's members can be sorted in to an array, but I am after a data structure with O(log(n)) insertion, removal and query.
Swift does not have a native ordered set type. If you use Foundation, you can use NSOrderedSet in Swift. If not, you have the opportunity to write your own ordered set data structure.
Update: Swift Package Manager includes an OrderedSet implementation that may be useful. It wraps both an array and a set and manages access to get ordered set behavior.
Update #2: Apple's Swift Collections repository contains an ordered set implementation.
On April 6th, 2021, a new package of Swift was released: Swift-Collection where three more data structures have been implemented. (OrderedSet, OrderedDictionary, Deque)
However, this package is in its pre-1.0 release state. As a result, it might not be stable.
Swift blog: Release of Swift Collections
At the time being there is no ordered set in Swift. Despite using NSOrderedSet on all Apple platforms, you can simply combine a Set with an Array to basically get the same effect. The Set is used to avoid duplicate entries, the Array is used to store the order. Before adding a new element to the Array, check if it is in the Set already. When removing an element from the Array, also remove it from the Set. To check if an element exists, ask the Set, it's faster. To retrieve an element by index, use the Array. You can change the order of elements in the Array (e.g. resort it) without having to touch the Set at all. To iterate over all elements, use the Array as that way the elements are iterated in order.

Traversing an object model recursively to search for a value

I need to recursively traverse a very large and complicated object model to search for a particular value of an ID.
The value I'm looking for is in a property called "ID", but objects with a particular ID might have many children, some of which are arrays, each having a different ID, and each of those children in turn can have a different ID and so on and so forth.
So if I give you an object, say $web, and you know that deep down in it's object model there is a value of an object that you are looking for. How do you look for it using recursion and reflection?
Note: This is a generic powershell/recursion/programming question even though the topic is SharePoint.
How about using Format-Custom? For example, getting a lot of nested member data from a directory info is done like so,
(gci)[0] | fc > test.txt
Will give some 8800 lines of data for expanded members.

Efficiently accessing array within array

I have a data type called Filter which has an NSMutableArray property which holds a bunch of FilterKey objects (different amount of keys for each filter). I have a bunch of these Filter objects stored in an NSMutableArray called Filters.
I have a UITableView for which each row is populated with data from one of the FilterKey objects. My question is, for a given row in the UITableView, how can I use the Filters array to find the right FilterKey (considering I've already put the Filters and Keys in order manually)?
Basically, I know I could just traverse through the Filters array and for each Filter object, traverse through all it's FilterKeys, but I'm wondering is there a better way to do this (ie better data structure, or something that would give me the right object faster?
Sorry if this is confusing if you have any questions please let me know in the comments.
Typically you would use sections and rows for this, where each section is a Filter and each row is a FilterKey.
It sounds like you just want to show the filter keys, and not have section headers for their filters (if I'm reading your post correctly). If you don't actually want headers, that's fine, just return 0 for tableView:heightForHeaderInSection: and nil for tableView:viewForHeaderInSection:.
All of this is really more for convenience than performance. It is unlikely that it will be much faster than running through the filters and adding up the counts of their keys. That kind of operation is extremely fast. But sections/rows maps your data better, so I'd probably use it anyway to keep the code simpler.
You can use NSMutableDictionary which is hash-mapped resulting in faster, easier, readable operations.
If you prefer arrays then there is no need to traverse to search for a specific value, you can use NSPredicate to filter your array.

How can you use sort descriptors and predicates with core data transformable fields?

I have an application which I wrote which used to work perfectly fine. There is new requirement that all data needs to be encrypted now, so I implemented encryption by making all my core data fields type transformable and writing custom transformers for each data type which encrypts/decrypts each element of data as it is written/read from the core data store.
The encryption works fine and I can see all the data. The problem is that sorting appears to be broken as does any even slightly complicated predicate (the ones that include subqueries).
I'm guessing that the sorting is being done on the values before they are sent through the transformer (namely, sorting is being done on the encrypted values). Is there a way I can get around this? I suppose I can try using a sort descriptor and specify my own selector to do the comparison and explicitly decrypt the values first. I'll post here if that works.
The predicate situation is a bigger problem though. It's strange that it seems to mostly work but then fails when I do subqueries (which are like joins across two objects in a relationship). Is there a known problem when using transformable values and predicates or maybe I have a bug in my transformers?
Here is an example of a predicate that no longer works:
[NSPredicate predicateWithFormat:#"isdeleted == NO AND (SUBQUERY(appuserMessages, $am, $am.recAppUserID == %# AND $am.isTrash == NO).#count > 0)", appuserid];
The predicate is performed on the Messages object which has a one-to-many relationship with AppuserMessages. This predicate is supposed to return all messages that are not isdeleted and have at least one appuserMessage where the recAppUserID is appuserid and isTrash is false. It used to work, but now returns nothing.
From more experimentation it seems that subquerys simply won't work when you have transformable data types.
Sort descriptors won't work either and it is understandable why. The sorting is left delegated to the database engine to do, so the sorting is done on the rows pre-transformation. In my case, that means they are sorted based on their (random) encrypted values instead of the decrypted ones.
The only solution seems to be to fetch the rows into an mutable array and then perform the sort on the array (using sortWithDescriptors).
As for the subqueries, I'm assuming its a similar problem. Probably the subquery is done by the database engine pre-transformation and therefore always fails. Again, the solution is to do as complicated as a query as you can in the fetch and then the rest of the query (the subquery part) with a filter on a mutable array of the results.

iPhone: NSSet keep sort order

I have an NSMutableArray which has about 18 objects. They are in a specific order that I want. I have to add these objects into an NSSet to be saved in Core Data.
But, once I pull them out of the NSSet using [myObject.items allObjects] it does not keep the original order that I added the objects as. How can I keep the order that I want, I don't want to have to resort them.
Sets do not have sort order because sets have no concept of order. Arrays have a fixed order because the order of elements in an array is what defines an array. A set by contrast is defined by the uniqueness of each individual object in a set. An array can have many duplicates of the same element at different indexes but a set can never store the same object twice.
Core Data uses sets because it needs to know exactly which objects relate to one another. In most cases, any ordering e.g. alphabetical, numerical etc is needed only by the UI and plays no part in the actual modeling of the real-world objects, events or conditions the data model simulates. For example, if you had a model of Department<-->>Employee, all employees belonging to a particular department would comprise a set. You might need to sort employees by name, date of birth, hire date etc but that would be just for display and would have nothing to do with the relationship.
If you need to model any kind of arbitrary order, you need to add an attribute that holds an attribute that you can sort on as needed. This is not overhead because the order becomes part of the real-world objects, events or conditions simulated by the model.
If you don't want to sort them you can add a property (e.g. int indexInList) to the objects which stands for the position in the list.
But sorting the list in respect to a property of the objects would be very easy too with
- (void)sortUsingSelector:(SEL)comparator
- (void)sortUsingDescriptors:(NSArray *)sortDescriptors
...