Collection Object operator for #firstObject Key-value coding KVC - cocoa

I'm often required to retrieve the 1st object belonging to a Set. (Using that object as a representative of that set.)
I envision a Collection Object operator, akin to the
#unionOfObjects
BUT clearly
#firstObject
Is it possible to create such a Collection operator!

Currently there's no way to define custom collection operators. However, due to some internal magic there is a funny solution:
NSSet *testSet = [NSSet setWithArray:#[#"one", #(1)]];
id object = [testSet valueForKey:#"#anyObject"];
NSLog(#"anyObject (%#): %#", NSStringFromClass([object class]), object);
UPD: Forgot to mention another handy trick: you can use #lastObject on NSArray!

Related

keyPathsForValuesAffectingValueForKey not called for all attributes

I am trying to observe changes to a transient attribute in my entity that is dependent on other attributes in the same entity. I want to do this by implementing keyPathsForValuesAffectingValueForKey:. The problem is that this doesn't seem to be invoked for all the attributes in the entity.
My entity has 10 attributes and about 5-6 relationships, and the keyPathsForValuesAffectingValueForKey is called 5 or 6 times with some mix of attributes and relationships, but not all of them, including the transient attribute that I'm really interested in.
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
if ([key isEqualToString:#"todoSectionTitle"])
{
NSSet *affectingKeys = [NSSet setWithObjects:#"todoStatus", #"todoStartDate", #"timeNow", nil];
keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKeys];
}
return keyPaths;
}
In this case, keyPathsForValuesAffectingValueForKey is called multiple times, but the key is never "todoSectionTitle" (a transient attribute). Neither is the key ever equal to "todoStatus" though that is a non-transient attribute. The key IS equal to "todoStartDate" in one of the times it is called. It can also be equal
What is the logic behind when keyPathsForValuesAffectingValueForKey: and which keys it is called for, and which keys it ignores? The docs don't seem to shed any light on this.
+keyPathsForValuesAffectingValueForKey: is part of Key-Value Observing (KVO). KVO only needs to call it if something observes a key on an instance of the class which implements it. (That includes any keys observed indirectly. For example, if something observes key "A", it will call the method for key "A". If it indicates that the value of "A" is affected by key "B", then it will also call it for key "B" to see if some other key(s) affect the value of "B".)
If nothing is observing todoSectionTitle or any key whose value is affected by todoSectionTitle, then KVO has no reason to call +keyPathsForValuesAffectingValueForKey: with "todoSectionTitle". In fact, KVO no way to know that there is such a key.
Bindings are built on top of KVO, so all of this applies to them, too.

Sort two-dimensional NSMutableArray using the last element the inner arrays

I have the following NSMutableArray:
(A|B|C|D|E|255,
F|G|H|I|J|122,
K|L|M|N|O|555)
I am trying to sort the objects in the array using the last component (255, 122, 555). Right now I have the following code:
[myArray sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
As expected, this method sorts the array by the first element (A, F, K).
I also read about NSSortDescriptor, for example:
NSSortDescriptor *sort = [[[NSSortDescriptor alloc] initWithKey:#"dateModified" ascending:YES] autorelease];
If I use it, it is not clear what I put as a parameter in initWithKey.
You can use a sort descriptor, which takes the last object of the "inner" arrays and sort by that.
Since sort descriptors use key-value coding (KVC), you need to be aware that arrays respond to valueForKey: in a special way - they pass a normal key on to each of the objects that they contain.
You also need to know that methods which do not take a parameter and return a value can be accessed through KVC is if they were normal properties.
All this adds up to the following:
Each of the objects contained in your array (i.e., the inner arrays) have a key that you want to sort by: lastObject
But since the objects are instances of NSArray they will normally pass the key on to the objects that they contain - which is not what you want.
You therefore need to use a special escape in the key name for that situation, which is #, making the actual key to use #lastObject
So to make a long story short, you can do what you want in this way:
NSMutableArray *array = ... // Your array
NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey: #"#lastObject"
ascending: YES
selector: #selector(localizedCaseInsensitiveCompare:)];
[array sortUsingDescriptors: #[sd]];
You'll notice the "#" in the key name, within the string.
This escape character also works for other collection classes, for instance if you want to access allKeys from a dictionary through KVC, the key you should use is #allKeys.
I would use sortUsingComparator:
[myArray sortUsingComparator:^NSComparisonResult(id obj1, id obj2){
return [obj1.lastPropertyForComparison compare:obj2.lastPropertyForComparison];
}
This method allows you to manually compare the properties or members of the objects that you want to order by. I use it almost exclusively for complex sorts, and I haven't noticed any performance differences.
UPDATE:
If your NSMutableArray contains NSArrays with the last object being the number you're trying to rank by, your comparator would be as follows:
[(NSNumber *)[obj1 lastObject] compare:(NSNumber *)[obj2 lastObject]]
Basically, you are grabbing the last object out of each NSArray, which you know is an NSNumber. You use the compare function to return NSOrderedAscending, NSOrderedDescending, or NSOrderedSame. I hope that helps.

Walking Core Data graph to-many relationships always seems awkward, is there a better way?

I'm able to get things working fine with Core Data and to achieve my desired results, but I always feel it very awkward when walking to-many relationships because NSSet is, for my typical purposes, fairly useless.
An example is if I have obtained a NSManagedObject of Entity "Zoo" with attribute "nameOfZoo" and to-many relationship "animalCages", the to-many relationship pointing to Entity "AnimalCage" which has attribute "nameOfSpecies" and to-many relationship pointing to Entity "IndividualAnimal"
Zoo [nameOfZoo] ->> AnimalCage [nameOfSpecies] ->> Animals
So, getting the top level Zoo object, that's simple. But then I want to get the data for nameOfSpecies "Canus Lupus". The code I want to write is this:
// Normal NSEntityRequest or whichever it is, I have no gripe with this
NSManagedObject *zoo = ..the request to get the one Zoo..;
// I want to get the object where the key "nameOfSpecies" is set to "CanusLupus"
NSManagedObject *wolf = [[zoo animalCages] object:#"Canus Lupus" forKey:#"nameOfSpecies"];
Obviously, I can't obtain wolf in this manner. Instead, I have to write like 10 lines of code (feels like 100 lines of code) to first obtain the set, then set up a search predicate request, and declare an error variable, execute the request, then get an array of the results, then get the first element of that array.. and if I want to walk further down the tree, to find the animal named "Wolfy" for instance, then I have to do it all over again.
Am I doing things correctly or am I foolishly an easier way? I guess I can put a category on NSSet, maybe I will, but I feel like there should be a built in better way. If not, why?
If you have a data model like this:
Zoo{
name:string
animalCages<-->>AnimalCage.zoo
}
AnimalCage{
nameOfSpecies:string
zoo<<-->Zoo.animalCages
animals<-->>Animal.animalCage
}
Animal{
name:string
animalCage<<-->AnimalCage.animals
}
The to find a specific AnimalCage by name of species for a given Zoo object:
NSString *soughtSpecies=#"Canis Lupis"; // normally this variable would be passed in to the method
NSPredicate *p=[NSPredicate predicateWithFormat:#"nameOfSpecies==%#", soughtSpecies];
NSSet *wolves=[[zoo animalCages] filteredSetUsingPredicate:p];
Or you can use objectPassingTest: if you like blocks.
If you use custom NSManagedObject subclasses, then you get custom accessor methods and can use self.dot notation so the above would be:
Zoo *zoo= // fetch the appropriate zoo object
NSString *soughtSpecies=#"Canis Lupis";
NSPredicate *p=[NSPredicate predicateWithFormat:#"nameOfSpecies==%#", soughtSpecies];
NSSet *wolves=[zoo.animalCages filteredSetUsingPredicate:p];
If you know before hand that you are going to have to find cages a lot, you could wrap the above up in a method on your Zoo class e.g.
#implementation Zoo
//... other stuff
-(AnimalCage *) cageForSpecieNamed:(NSString *) specieName{
NSPredicate *p=[NSPredicate predicateWithFormat:#"nameOfSpecies==%#", specieName];
NSSet *wolves=[self.animalCages filteredSetUsingPredicate:p];
return [wolves anyObject]; // assuming one cage per species
}
Objective-c is intentionally verbose because it was supposed to be "self documenting" and the editor written for the language at the beginning had autocomplete. So, if your used to a more expressive language it might seem you are doing a lot of work but logically you aren't.

Question about a terminology which implements something like this list.Add(new{a=1, b=2})

What is the terminology for the usage of "new" in:
list.Add(new{a=1, b=2})
And what type should I replace the T in List getList if I want to use the list as the returned value? I don't want to replace T with "object" because I want to parse it in Linq query.
Thanks.
Since you did not specify a type: new {1), it's called object initializers with anonymous types. (MSDN Explaining them) The Object Initializer part is where you do { a=1, b=2}.
If you want to be able to reference a type, you will have to create a type and stuff the values in.
list.Add(
new MyType() {
a=1,
b=2
});
If you are just going to be pairing two items look into using the Pair Class. There is also a Triplet Class just in case you might want to store 3 items.

How to sort an NSArray of objects by their class?

I have an NSArray of objects that all subclass with their different types from a more abstract class.
I would like to sort the array by the object's class type. For example:
NSArray with CLASSA CLASSB AND CLASS C subclassed from CLASSz
myArray = {C, B, A}
Sort myArray decending: {A, B, C}
I see sort descriptors and that seems like it's the right path but I am comparing isKindOfClass which is not a property so can not be used in the NSSortDescriptiors thing.
Thanks for any help.
Well, the biggest hurdle I see is that you're probably going to need a custom property on Class objects which you could use as the key of an NSSortDescriptor. Unfortunately, there's no real way to add methods/categories to Class objects.
So what I would probably do is use NSStringFromClass() to convert your Class objects into strings, then use an NSString category to add a custom comparator method (something like compareToClass:) that converts the string back to a Class, does the subclass determination, and then returns the appropriate ordering constant.
From there, you can use NSArray's sortedArrayUsingSelector: method to get them in order.

Resources