iCloud doesn't support ordered sets.. alternative solution? - iphone

iCloud doesn't support ordered sets for relationships, only sets. Right now, i've made an attribute called 'entryIndex', where it stores it's own index value that it's given. When the user deletes the object at a specific index, I want to identify the object and change the value of the objects with higher indexes. How do I do this?

Assuming you have consecutive indexes and want to keep them "tight" without gaps:
NSArray *filtered = [fetchedObjects filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:#"entryIndex > %#",
deletedObject.entryIndex]];
for (NSManagedObject *obj in filtered) {
obj.entryIndex = [NSNumber numberWithInt:[obj.entryIndex intValue]-1];
}
[self.managedObjectContext save:nil];

Related

removing an object from a fetchedResultsController fetchedObjects

Is it possible to remove an object from a fetchedResultsController fetchedObjects?
For example I have the following code:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"pack.packName IN %#", allowedPackNames];
for (int i = 0; i < [tempFetchResults.fetchedObjects count]; i++){
Author *author = [tempFetchResults.fetchedObjects objectAtIndex:i];
NSSet *filteredQuotes = [author.quotes filteredSetUsingPredicate:predicate];
if ([filteredQuotes count] > 0){
author.quotes = filteredQuotes;
} else {
//remove this author from the fetchedObjects array
}
}
How can I do this?
To remove the object from the data store:
[self.managedObjectContext deleteObject:object];
[self.managedObjectContext save:nil];
[self.fetchedResultsController self.fetchedResultsController.fetchRequest];
[tableView reloadData];
To just remove the object from the fetched results controller array, you need to change the predicate. Make sure you disable cache (or change the cache name) for this to work.
I think you could define a property 'excluded' or something like that of integer type and incorporate that property into your fetch request predicate. Now when you mark a quote as excluded, fetched results controller will do all the heavy lifting for you without refetching and all.
Update #1
Addressing the bigger issue here I think using subquery in your fetched results controller predicate is much better idea.
Try using:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(quotes, $x, $x.pack.packName IN %#).#count > 0", allowedPackNames];
as a predicate for your fetch request for fetched results controller and forget about manual filtering.
Basically what this subquery should do for you is filter out all authors that have quotes count fitting your packName criteria. I admit I did not test this query. If you say this won't work for you I will go through the trouble and test it myself.

Performance Problem while retrieving custom objects from array

I create a custom object that has some properties like ID and Title,description etc...
And I add it to an array. (That array may contains more than 500 values).
And I use the following code to retrieve custom objects,
-(CustomObjects *)getObjectWithId:(int)id {
CustomObjects *objCustomObjects = nil;
for (CustomObjects *customObjects in arrayCustomObjects) {
if (customObjects.id == id) {
objCustomObjects = customObjects;
break;
}
}
return objCustomObjects;
}
But It has some performance problem, because I use the function to call on UIScrollview pinch.
How can I improve performance in fetching the objects?
thanks in advance,
A dictionary is better for this. The only catch is that you can’t have a NSDictionary with primitive int keys, so that you have to wrap the id in an NSNumber.
- (void) addCustomObject: (CustomObject*) obj {
NSNumber *wrappedID = [NSNumber numberWithInt:[obj idNumber]];
[dictionary setObject:obj forKey:wrappedID];
}
- (CustomObject*) findObjectByID: (int) idNumber {
NSNumber *wrappedID = [NSNumber numberWithInt:[obj idNumber]];
return [dictionary objectForKey:wrappedID];
}
A dictionary (also called hash table) does not have to go through all the values to find the right one, it has all the values arranged cleverly according to the keys so that it can jump to the right one or close to it. What you are doing with the array is called linear search and it’s not very efficient.
Better you can use NSDictionary with id as the key. You can easily fetch the object from the dictionary.
Is it Ok for your requirement?
You could use an NSPredicate that checks whether id equals the one you're looking for, and simply filter the custom objects using this predicate by calling filteredArrayUsingPredicate:.
To improve performance, I would try to postpone whatever you're trying to calculate by not directly calling the function that does the heavy work in your scroll view, but rather call [self performSelector:... withObject:nil afterDelay:0]; which postpones the calculation to the next runloop cycle. If you check if there's already a calculation scheduled before you call performSelector you should actually be able to reduce the frequency of the calculation while maintaining a crisp interface.
You must ditch the array in favor for a dictionary if you want to have fast lookups.
If you want to access objects both by key and index then you need to the objects around in two collections, and make sure they are in sync.
I have already done a helper class for this named CWOrderedDictionary. It's a subclass of NSMutableDictionary that allows for access to objects by both keys (as any dictionary do), and by index using methods identical to NSMutableArray.
My class is available to use for inspiration or as is from here: https://github.com/jayway/CWFoundation/
Use NSPredicate:-
You will receive the filtered array with the object that has the id you passed;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %#", id];
NSArray *filtered = [arrayCustomObjects filteredArrayUsingPredicate:predicate];
Instead of intjust use [NSNumber numberWithInt:] , i did some changes in your given code.
-(CustomObjects *)getObjectWithId:(NSNumber* )id {//changed int to NSNumber
CustomObjects *objCustomObjects = nil;
NSPredicate *bPredicate = [NSPredicate predicateWithFormat:#"SELF.id==%#",id];
NSArray *result = [array filteredArrayUsingPredicate:bPredicate];
//return filtered array contains the object of your given value
if([result count]>0)
objCustomObjects = [result objectAtIndex:0];
}
return objCustomObjects;
}

Fetch Specific Number of Random Rows from CoreData

I'm using the code below to Fetch a queried set of all rows using CoreData matching the search criteria: itemType = 1.
But what I need to do is to Fetch a specific number of Random rows from the data instead.
For example, instead of retrieving all 100 rows of data in which the column name dataType = 1, I need to get 25 rows randomly in which dataType = 1.
I'm hoping there is relatively painless solution.
Any help is appreciated.
lq
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:#"MyAppName"
inManagedObjectContext:[self managedObjectContext]]];
NSError *error = nil;
NSPredicate *predicate;
NSArray *fetchResults;
predicate = [NSPredicate predicateWithFormat:#"(itemType = %i)", 1];
[request setPredicate:predicate];
fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
if (!fetchResults) {
// NSLog(#"no fetch results error %#", error);
}
self.mutableArrayName = [NSMutableArray arrayWithArray:fetchResults];
[request release];
You can not actually fetch random rows. A reasonable randomization strategy may be to fetch all of the objects matching your predicate, and then randomly select a specific number of objects.
Anyway you can use the following methods of NSFetchRequest:
- (void)setFetchLimit:(NSUInteger)limit
- (void)setFetchOffset:(NSUInteger)limit
Basically, setFetchLimit allows you to define how many rows you want to fetch (in your case you will set limit to 25), while setFetchOffset defines the offset at which rows will begin being returned (see the documentation of the fetchOffset property for details).
This is not a random process, but you may randomly generate the offset. However, it is worth noting here that, depending on the offset, you may then fetch a number of objects falling between zero and your fetch limit.
You could also use reference approach. When you sort by view counts.
I posted long time ago about it: http://www.alterplay.com/ios-dev-tips/2010/06/fetch-random-record-with-coredata.html
Sorry for formatting. it's broken after switching from Blogger to Wordpress.

iPhone SDK: Core Data and uniquing?

Either I'm not understanding what the term "uniquing" means in Core Data, or I'm not fetching my data properly. I have a pretty simple data model. Three entities: Community, Asset, and Category. Each Community has a relationship to multiple categories. Each category has a relationship to multiple assets. Each asset that is created must have one and only one category.
In the code I've posted, I'd like to output all the categories that a specific community has into the console. I thought that because of Core Data's uniquing capability, only one category of the same name could exist at a time (name is the only attribute for a category). However, when I print to the console, I'm getting duplicate category names.
// Fetch Community instances in the database, and add them to an NSMutableArray
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *community = [NSEntityDescription entityForName:#"Community" inManagedObjectContext:managedObjectContext];
[request setEntity:community];
// Only return the community instances that have the cityName of the cell tapped in the CommunitiesNonEditableTableViewController
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(cityName like %#)", cellCityName];
[request setPredicate:predicate];
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error.
}
// Set communitiesArray with mutableFetchResults
[self setCommunitiesArray:mutableFetchResults];
[mutableFetchResults release];
[request release];
// Creates a community instance using the community stored in the array at index 0. This is the only community in the array.
Community *communityInstance;
communityInstance = [communitiesArray objectAtIndex:0];
// Retrieves existing categories of assets in the community, and adds them to an NSSet
NSSet *communityCategoriesSet = communityInstance.categories;
// Converts NSSet to an NSArray with each category as an index
NSArray *communityCategoriesArray = [communityCategoriesSet allObjects];
// For loop that iterates through the array full of categories, retrieves the names of each category, and adds it to an NSMutableArray
categoryNames = [[NSMutableArray alloc] init];
int i;
for (i = 0; i < [communityCategoriesArray count]; i++) {
Category *categoryInstance;
categoryInstance = [communityCategoriesArray objectAtIndex:i];
[categoryNames addObject:categoryInstance.name];
}
// Prints array full of category names to console
NSLog(#"%#", categoryNames);
When I execute this, I get duplicate names in the console. Why?
Uniquing means that each object in the object graph is itself unique. It does not mean that the attributes of any two objects are not identical. Uniquing is about relationship not attributes. No two objects can occupy the exact same position in the object graph.
As to why you get multiple categories in the output: The simplest explanation is that communityInstance.categories is a to-many relationship. (Since it has a plural name and you assign it to set.) In a to-many relationship, the context does not force a single object on the other end of the relationship.

How to insert an object at a given index in iphone-sdk

I want to insert a object at a given index. and If Is there no object at the index, I want to know that.
Is NSDictionary good choice?
Is there another good solution?
// Initailization
NSMutableDictionary *items = [NSMutaleDictionary dictionary];
...
// insert an object.
[items setObject:item forKey:[NSNumber numberWithInt:3]];
...
// I want to know that there is an object at a given index.
item = [items objectForKey:[NSNumber numberWithInt:4]];
if (item)
// exist
else
// non exist
Of course there is the NSArray class, for an indexed version of NSDictionary, kind of. However, the indexes in an NSArray should be subsequent, so the index begins at 0 and then increments with every object.
So when you want to use a random index, you should go with NSDictionary and you're good. The code you provided is absolutely valid and works correctly.