traverse Core Data object graph with added predicate? - objective-c

I want to load a client object and then pull their related purchase orders based on whether they have been placed or not, purchase orders have an IsPlaced BOOL property.
So I have my client object and I can get all purchase orders like this, which is working great:
purchaseordersList =[[myclient.purchaseorders allObjects] mutableCopy];
But ideally I would actually like 2 array's - one for each order type: IsPlaced=YES and IsPlaced=NO
How do I do that here? Or do I need to do another fetch?

First, there is no reason to be turning the set into an array unless you are sorting it and there is no reason to be turning that array into a mutable array. Did you get that from some example code?
Second, you can filter an array or a set by using a predicate so you can create two sets (or arrays) easily via:
NSSet *placed = [[myclient purchaseorders] filteredSetUsingPredicate:[NSPredicate predicateWithFormat:#"isPlaced == YES"]];
NSSet *notPlaced = [[myclient purchaseorders] filteredSetUsingPredicate:[NSPredicate predicateWithFormat:#"isPlaced == YES"]];
If you are wanting to use this for a UITableView then look into a NSFetchedResultsController instead. It will save you a LOT of boiler-plate code.
Do you remember what example code you got that from? Been seeing that -mutableCopy a lot lately and would love to quash it. :)

Related

how to add object in NSMutableArray using macro

for now i am creating my NSMutableArray using:
#define ARRAY_OF_ORDER_SOURCE [NSArray arrayWithObjects:DICTIONARY_OF_ORDER_SOURCE_ALL,DICTIONARY_OF_ORDER_SOURCE_ECOMMERCE,DICTIONARY_OF_ORDER_SOURCE_PHYSICAL,DICTIONARY_OF_ORDER_SOURCE_INVOICE,DICTIONARY_OF_ORDER_SOURCE_RECURRING,DICTIONARY_OF_ORDER_SOURCE_SALESVU,DICTIONARY_OF_ORDER_SOURCE_RESERVATION,nil]
i want to do some thing like:
if(somethingIstrue)
[ARRAY_OF_ORDER_SOURCE addObject:DICTIONARY_OF_ORDER_SOURCE_ALL]
if(somethingElseIstrue)
[ARRAY_OF_ORDER_SOURCE addObject:DICTIONARY_OF_ORDER_SOURCE_ECOMMERCE]
i am doing this as i need this array in my whole project, i have this in constant.h file.
how can i acheive this using macro??
Thanks.
If you really want to have a macro for this you can have a multiline macro and placed there the logic you want. It is not totally clear to me what you want to achieve but instead of macro I would prefer to have a category on NSMutableArray returning the array or some kind of Util class doing so.
There are numerous things wrong with your question. For starters, you claim you are creating an NSMutableArray, but you are in actuality creating an NSArray. You then try to addObject on the immutable array, which you cannot do.
In your line (note I modified it to add a comment):
if(somethingIstrue) {
// The NSArray isn't assigned to anything and tries to addObject to an NSArray
[ARRAY_OF_ORDER_SOURCE addObject:DICTIONARY_OF_ORDER_SOURCE_ALL]
}
you are not assigning the array to anything (as I already noted it won't work because it is trying to add to an NSArray).
I think you want to do something like:
NSMutableArray *orderedSource = [NSMutableArray array];
if (somethingIsTrue) {
[orderedSource addObject:addObject:DICTIONARY_OF_ORDER_SOURCE_ALL];
}
if (somethingElseIsTrue) {
[orderedSource addObject:addObject:DICTIONARY_OF_ORDER_SOURCE_ECOMMERCE];
}
The question you have to ask yourself is why do you insist on using a macro? You have no real design/approach here, which is why your ideas are coming across as scattered.
If you need to consistently create an array based on a set of constraints, one approach would be to create a class which can vend for you the array you want based on criteria. Or you can just do it where you need to using the approach above.

Filling NSMutableArray for later use in obj-c

How do you fill a NSMutableArray with a set capacity for later use?
Basically I want to set up a NSMutableArray to act as a map for my game objects, so I have this line...
gameObjects = [[NSMutableArray alloc] initWithCapacity:mapWidth*mapHeight];
Which I had hoped would create and fill my MutableArray so I can get then access it with this kind of index...
int ii = (cellY*mapWidth)+cellX;
NSDictionary *currentObject = [gameObjects objectAtIndex:ii];
But I just learned initWithCapacity doesn't fill the array, so should I create blank objects to fill it with, or is there a Null that I can fill it with? Also would I do that with 2 for loops or is there an instruction something like "initWith:myObject" ?
I want to be able to check at a certain index within the array to see if there's an object there or not, so I need to be able to acces that index point, and I can only do that if there's something there or I get an out of bounds error.
I'll be using this NSMutableArray pretty much as a grid of objects, it's a 1 dimensional array organised as a 2 dimensional array, so I need to be able to fill it with mapWidth*mapHeight of something, and then calculate the index and do a check on that index within the array.
I've looked on here and googled but couldn't find anything like what I'm asking.
Thanks for any advice.
I think what you are looking for is [NSNull null]. It is exactly what you want- a placeholder value.
You can find more information on the topic in this question.
initWithCapacity is just a performance optimization -- it has no effect on the array behavior, it just keeps the code "under the covers" from having to repeatedly enlarge the internal array as you add more entries.
So if you want a "pre-allocated" array, you'd need to fill it with NSNull objects or some such. You can then use isKindOfClass to tell if the object is the right type, or simply == compare the entry to [NSNull null]. (Since there's only ever one NSNull object it always has the same address).
(Or you could use a C-style array of pointers with nil values for empty slots.)
But you might be better off using an NSMutableDictionary instead -- no need to pre-fill, and if the element isn't there you get a nil pointer back. For keys use a NSNumber object that corresponds to what would have been your array index.
initWithCapacity only hints to NSMutableArray that it should support this many objects. It won't actually have any objects in it until you add them. Besides, every entry in the array is a pointer to an object, not a struct like you'd normally have in a standard c array.
You need to change how you're thinking about the problem. If you don't add an object to the array, it's not in there. So either you pre-fill the array with "empty" objects as you've said, which is weird. Or you can add the objects as you need them.

Distinct Object using NSPredicate

I have an NSArray of custom objects. Consider that the custom objects have a PageNumber property. I would like to filter my NSArray with a condition like "customObject.PageNumber is distinct".
I know I can loop through the array and eliminate object with duplicate pageNumbers. But is there any easy way to do it? I have tried,
[myarray valueForKeyPath:#"distinctUnionOfObjects.pageNumber"];
It is giving me the unique page numbers (like 7, 8, 9). But I want the custom object itself rather than just page numbers. Can any predicate help me?
I have created a simple library, called Linq to ObjectiveC, which is a collection of methods that makes this kind of problem much easier to solve. In your case you need the Linq-to-ObjectiveC distinct method:
NSArray* itemsWithUniquePageNumbers = [items distinct:^id(id item) {
return [item pageNumber];
}];
This returns an array of objects, each one with a unique page number.
Yes, that is possible with the help of NSPredicate
customObject=[(NSArray*)[myArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self.PageNumber==%d",pageNumber]] lastObject];
//pageNumber is an integer
The filtered array is an NSArray of your custom objects which is the result of filtering using the predicate. Since your page number is unique, it will return only an array of one object. We get that by passing lastObject message to it.
Refer:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/predicates.html#//apple_ref/doc/uid/TP40001798-SW1

Merge NSMutableArray with a NSArray, filtering the duplicates

I have two arrays, an NSMutableArray and an NSArray. The NSMutableArray is the "store", it stores results from a source of NSArrays. Every 5 minute, a new NSArray comes in and the data needs to be filtered and sorted.
Sorting by date is pretty easy, so I managed to get the NSArray sorted by NSDate. Sorting the other array is not necessary, as it would only cause confusion with the user.
What I want to do: the NSArray has a lot of different objects that all respond to -[object name], returning an NSString. The NSArray needs to be merged into the NSMutableArray, only adding new objects.
The merging itself is no problem, but performance is. The NSMutableArray can contain up to 3000 items, and the NSArray can contain up to 250 items, although usually only 5 or 6 of these have to be merged into the NSMutableArray.
So, my question is: how do you merge two arrays in Objective-C, filtering the duplicates, without iterating (250*3000) times?
Tom
Edited to clarify something
The "duplicate" objects are objects that are duplicate to the user but not to the code. They have the same name, but not the same address.
More clarification: #"value" != #"value" // true
Is name a property of the objects being stored in the arrays? If so, you could use a fairly simple NSPredicate to filter the immutable array before adding the results to the mutable one. Here's an example:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"NONE name == %#.name", mutableArray];
resultsArray = [immutableArray filteredArrayUsingPredicate:predicate];
[mutableArray addObjectsFromArray:immutableArray];
How about this:
[mutable removeObjectsInArray:newArray];
[mutable addObjectsFromArray:newArray];
It isn't the fattest, but is easy to implement :)
Edited to remove some stupidity (left plenty, though)
A couple of options:
Remove all matching objects from the NSMutableArray using removeObjectIdenticalTo. This requires iterating through the smaller array, but as you note they're commonly small. Then,
Add all of the items from the new array using addObjectsFromArray
Or... well, it actually might be faster to instead:
Iterate through the new array looking for matches with indexOfObjectIdenticalTo, using addObject to add in non-matching objects.
Costly either way, but doable.
I would probably start by creating a new mutable array which contains the contents of your NSMutableArray and NSArray. Then, sort the new array based on the name property and then run through the array once, only pulling out the unique items.
Can you use NSSet and NSMutableSet instead? That could help deal with the duplicates issue.
Edit:
Based on your comments, you could use an NSSet to check for object membership quickly, in addition to your array. It'd require a bit more memory, but if you don't mind that, it could allow you to check really fast. You'd have your NSMutableArray backing store, and then an NSSet to keep track of object membership. You'd maintain the invariant that the NSMutableArray does not contain duplicates. You could use code like this:
// Assume that arrayStore is an NSMutableArray * instance variable
// Also, storeSet is an NSMutableSet * ivar
- (void)addObjectsFromArray:(NSArray *)data
{
for (id item in data) {
if (![storeSet member:item]) {
// Will have to keep arrayStore sorted somehow
[arrayStore addObject:item];
[storeSet addObject:item];
}
}
}
You only have to iterate through the NSArray. I'm not sure how NSSet is implemented off the top of my head, but checking for membership won't be an O(n) operation like it is for an unsorted array.
It's not the most efficient method, but it works well with what you already have in place, with minor modifications.
There are likely many ways to dramatically improve performance, but to be able to suggest any, we really need to know more about what the objects in the arrays "are": what do they represent? How are they being used? (For example, are the items in the store array being displayed in a table view?)
NSMutableDictionary, NSMutableSet, etc. could be combined with NSMutableArray to organize and implement the model in an efficient manner.
For example, let's say we know the object represents a person: MDPerson. A person has a gender, a date of birth, a name, a unique id, and a set of attributes that can change. Given this higher level understanding of what the object represents, we know that 2 people are equal only if their unique ids are the same (in other words, 2 different people can have the same name, gender, and date of birth). Let's say that your main NSMutableArray is made up of a list of 3000 people. The incoming array is made up of 500 people which are already in the main NSMutableArray. A few of these 500 people instances might have "updated" attributes, which means that their instance in the main array needs to be updated with that info.
Given that understanding, it's clear that the main list should be implemented as an NSMutableDictionary rather than an NSMutableArray. In the dictionary, the person's unique id would be the key, and their person instance would be the value for the key. You could then loop through the incoming array of 500 persons only once:
// main dictionary is called personIDsAndPersons
for (MDPerson *person in incomingPersons) {
MDPerson *existingPerson = [personIDsAndPersons objectForKey:[person uniqueID]];
// if nil, the person doesn't exist
if (existingPerson) {
// update the existing person's attributes
[existingPerson setUniqueAttributes:[person uniqueAttributes]];
}
}
Again, without knowing more of the details or having a higher level understanding of what the objects are, we're really just shooting in the dark.
You mention that 2 items are only the same if they have the same name. So, does that mean that each item in the main array of 3000 objects each have a unique name? If so, you could use an NSMutableDictionary to allow access to the objects in an efficient manner by having the keys in the dictionary be the name and the values be the object instance. You could then use a separate NSMutableArray that's used merely for display purposes: it allows an ordered, sorted organization of the same objects that are stored in the NSMutableDictionary. Remember that when you add an object to an array or a dictionary, normally you're not creating a new copy, you're just retaining the existing object.

Add missing objects to create an ordered collection

The subject is vague because I'm not sure how to articulate in one sentence what I want.
Here goes:
I have an NSArray of NSDictionaries. Each NSDictionary represents one day of the calendar year. Each NSDictionary has a key "date" with a value of NSDate. There should be 365 NSDictionary items in the array. The dictionary is created by a server that I don't control, and it sometimes is missing as many as 100 days.
I need to ensure the array has 365 dictionaries, each one day later than the next.
I currently sort the array by date, iterate through it, copying the NSDictionaries from the current array to a new array. While so doing, I compare the current Dictionary's date value with the date value for the next dictionary. If there is more than one day between the two dates, I add enough new dictionaries to the new array to cover those missing days (and set their dates accordingly), then continue through.
Since the dates are supposed to ordered, I wonder if there is not already a mechanism in the framework or language that I can use to say "Here is an array, and this keypath is supposed to be consecutive. Find and create the elements that are missing, and here's a block or method you can use to initialize them".
Something about my method just feels poorly implemented, so I turn to you. Thoughts?
Thanks.
The way you did it sounds perfectly sane, and there is nothing to my knowledge that will do it automatically in the base framework.
This code will sort them.
NSArray *dates; // wherever you get this...
NSArray *sortedDates = [dates sortedArrayUsingComparator:^(id obj1, id obj2)
{
return [[obj1 valueForKey:#"date"] compare:[obj2 valueForKey:#"date"]];
}];
As for creating the missing entries, you'll have to do that yourself.
You don't need to do the sort:
Create an array with 365 (or 366) placeholder dictionaries (you can possibly use the same one for all slots, or use NSNull)
iterate through the passed in array and figure out which day each of the dictionaries is for. Place each dictionary in its rightful slot in your array.