My app shows the following error when type into a UISearchBar quickly
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 206 beyond bounds [0 .. 13]
when typing slowly, search works just fine
-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)text
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if(text.length == 0)
{
isFiltered = FALSE;
}
else
{
filteredTableData = [[NSMutableArray alloc] init];
sortedCustomerID= [[NSMutableArray alloc]init];
sortedDefaultsShipingID=[[NSMutableArray alloc]init];
isFiltered = true;
if (text !=nil)
{
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"lastName contains[cd] %# ",text];
[fetchedResultsController.fetchRequest setPredicate:predicate];
}
else
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"All"];
[fetchedResultsController.fetchRequest setPredicate:predicate];
}
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error])
{
// Handle error
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
_fetchedObjects = fetchedResultsController.fetchedObjects;
for (int i =0 ; i<_fetchedObjects.count ; i ++)
{
[filteredTableData addObject:[[_fetchedObjects valueForKey:#"lastName"]objectAtIndex:i]];
[sortedCustomerID addObject:[[_fetchedObjects valueForKey:#"customerID"]objectAtIndex:i]];
[sortedDefaultsShipingID addObject:[[_fetchedObjects valueForKey:#"defaultShippingID"]objectAtIndex:i]];
}
}
NSLog(#" name=%# customerID=%# shippingID=%#", filteredTableData,sortedCustomerID,sortedDefaultsShipingID);
dispatch_async(dispatch_get_main_queue(), ^{
// Return data and update on the main thread
// Task 3: Deliver the data to a 3rd party component (always do on the main thread).
});
});
}
With most exceptions you get quite a bit of additional information that can help you figure out what is going wrong.
In this case, the exception description is telling you that you tried to access an NSArray element that does not exist. It would appear that the NSArray object in question is _fetchedObjects. Furthermore, based on the name, it would seem that it is an ivar.
So consider what is happening here. Character is entered in search bar. Async operation gets launched and data is retrieved, stored in _fetchedObjects and then accessed. However, what happens when several of these operations get created very quickly and each of them try to access the same _fetchedObjects?
I would consider storing the search results in a local variable and then assigning it to an ivar/property at the end of the async op if you really need to store it.
Try changing your for loop to
for (int i =0 ; i<_fetchedObjects.count ; i ++)
{
[filteredTableData addObject:[[_fetchedObjects objectAtIndex:i] valueForKey:#"lastName"]];
[sortedCustomerID addObject:[[_fetchedObjects objectAtIndex:i] valueForKey:#"customerID"]];
[sortedDefaultsShipingID addObject:[[_fetchedObjects objectAtIndex:i] valueForKey:#"defaultShippingID"]];
}
Related
I had an application in which I need to remove elements from my core data object which is not present in an array of dictionary.
-(void)removeoldvalueswhichisnotpresentinnewone:(NSArray *)array{
for(int j=0;j < [array count]; j++){
NSString *pred = [NSString stringWithFormat:#"no !=\"%#\"",[array objectAtIndex:j]];
NSArray *allRes = [self getObjectsOfType:#"Cr" withPredicate:pred];
NSLog(#"%#",allRes);
if ([allRes count] > 0) {
#try {
for(int i=0;i < [allRes count]; i++){
[[self managedObjectContext] deleteObject:(Cr *)[allRes objectAtIndex:i]];
}
[self save];
}
#catch (NSException *exception){
// NSLog(#"Del Warning: Caught %#: %#", [exception name], [exception reason]);
}
}
}
}
But it is not working fine.Can anybody points me where I am going wrong?
Some thoughts:
don't build predicates with NSString's stringWithFormat, use NSPredicate's predicateWithFormat.
Is no a number? If so you should not be putting quotes around %#.
"NO" is a reserved word; try using a different attribute name.
Is your logic correct? It will delete all the items that don't match the first object in the array (so only those matching first object will remain), then loop and delete all items that don't match the second object, etc (which probably deletes those left by the first pass through the loop). You should only delete objects if they don't match all the objects in the array. You could instead use an NOT IN predicate:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"NOT (attribute IN %#)", array];
You won't then need the outer loop.
Hi in my application I am setting the value for NSManagedObject while I am trying to set a value app is crashing.Here is the code and error message.
NSManagedObject *object3 = [threadManagedObjectContext objectWithID:[object1 objectID]] ;
for (int i=0;i<[array1 count];i++)
{
NSDictionary *keyValue=[array1 objectAtIndex:i];
[object3 setValue:[[keyValue allValues] lastObject] forKey:[[keyValue allKeys] lastObject]] ;
}
Error: Terminating app due to uncaught exception 'NSGenericException', reason:was mutated while being enumerated
Can any one please help me.
In your code (not the provided) , you're changing a collection while looping/iterating.
Example (not allowed):
for (MyClass *myClassObj in collectionOfMyClass) {
[myClassObj setClassVar: aVar]
}
Solution:
Make a temporary collection of the objects you want to set. Set all of them back outside of your loop.
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for (MyClass *myClassObj in collectionOfMyClass) {
[tempArray addObject:aVar];
}
[myClassObj setClassVars: tempArray];
You can try below solution for updating the object...
NSManagedObject *object3 = [threadManagedObjectContext objectWithID:[object1 objectID]] ;
int i=0;
for (NSDictionary *keyValue in array1)
{
[[object3 setValue:[[keyValue allValues] lastObject] forKey:[[keyValue allKeys] lastObject]] ;i++;
}
NSError *error;
bool result = [[fetchedResultsController threadManagedObjectContext] save:&error];
if (!result) {
NSLog(#" error saving context, %#, %#", error, error.userInfo);
}
In your code while Looping/Enumerating you are setting value..So it is crashing...!
Hope it helps you....
I created an RSS reader for a blog. I am retrieving the articles of the blog and am filling a UITableView with them in a navigation controller. When a user taps in a row, a web view comes up with the original article on the blog. I use Core Data in order to save the title, link and date of the articles with the following code:
NSManagedObjectContext *context = [self managedObjectContext];
rssFeed = [NSEntityDescription insertNewObjectForEntityForName:#"RSS" inManagedObjectContext:context];
[rssFeed setValue:title forKey:#"title"];
[rssFeed setValue:link forKey:#"link"];
[rssFeed setValue:date forKey:#"date"];
Then I call it with the following code:
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"RSS"];
self.feedArray = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
NSManagedObject *matches = nil;
if ([_feedArray count] == 0)
{
NSLog(#"No matches");
}
else
{
for (int i = 0; i < [_feedArray count]; i++)
{
matches = _feedArray[i];
}
}
If I print the feedArray in the table view, the results are not so clear. I get something like null between the articles, and they aren't in the right order. Can anyone help me understand what happens?
And the error message:
Terminating app due to uncaught exception 'NSRangeException', reason: ' -[__NSArrayM objectAtIndex:]: index 25 beyond bounds [0 ..
24]'
I hope this isn't a duplicate question. I can't seem to find anything similar. Most core data questions seem to be about new object creation...
I have a program with a database of around 23,000 items. I'm attempting to create an export/import function to send data to other devices (not linked with iCloud).
The export works just fine, as does the email...
I have the import functioning, but it functions slowly (and, more on this later, doesn't seem to work well with the iPhone 5 or iPad 3)
I have a function that parses the data I'm importing into an NSArray (_importedRows), then I run the following code:
self.managedObjectContext = [(AppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSManagedObjectContext *ctx = self.managedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"CHECKLIST"
inManagedObjectContext:ctx];
[fetchRequest setEntity:entity];
ImportedData *importedData;
NSString *verify;
NSError *error = nil;
NSManagedObject *updatedObject;
NSArray *matchingItems;
for (int i = 0; i < [_importedRows count]; i++) {
importedData = [_importedRows objectAtIndex:i];
verify = importedData.uniqueID;
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"uniqueID == %#", verify]];
[fetchRequest setFetchLimit:1];
matchingItems = [ctx executeFetchRequest:fetchRequest error:&error];
for (updatedObject in matchingItems) {
HUD.detailsLabelText = [NSString stringWithFormat:#"Updating %#" , [updatedObject valueForKey:#"figureName"]];
[updatedObject setValue:importedData.numberOwned forKey:#"numberOwned"];
[updatedObject setValue:importedData.numberWanted forKey:#"wishList"];
[updatedObject setValue:importedData.availableTrade forKey:#"tradeList"];
}
[ctx save:&error];
if (error != nil) {
NSLog(#"error saving managed object context: %#", error);
}
}
Basically, I'm grabbing a core data entity, and then looping through my array checking for matches. When I find a match (the uniqueID predicate), I'm updating the object with the imported data. This code works fine on my iPhone 4s, but rather slowly. 4,000 items takes around 4-5 minutes. Am I doing anything blatantly wrong? Should I be calling the save function more frequently?
As a bonus, for some reason this code almost never works when I test it on an iPhone 5. 9 times out of 10 (and 50% of the time on my iPad 3) I get a
"Jan 14 08:06:44 : * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil'"
in the console. Thoughts?
Let me know if more details are needed!
UPDATE:
It seems that handleOpenURL is being called twice... once in applicationdidfinishlaunching
NSURL *url = (NSURL *)[launchOptions valueForKey:UIApplicationLaunchOptionsURLKey];
if (url != nil && [url isFileURL]) {
[self.window.rootViewController performSelector:#selector(showWithLabel:) withObject:url afterDelay:6];
}
and once here:
-(BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{ if (url != nil && [url isFileURL]) {
[self.window.rootViewController performSelector:#selector(showWithLabel:) withObject:url];
}
return YES;
}
I have to lave both those in the app delegate, otherwise the function won't always get called (once is for when the application launches, and once if it the application was already in the background, I believe) - I've added a check to prevent it from launching a second time within the showWithLabel thread, but it doesn't seem like that is a very elegant solution...
UPDATE: #mundi advised cleaning up the fetchedresults code as follows:
NSArray *importedIDs = [_importedRows valueForKeyPath:#"uniqueID"];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
fetchRequest.entity = [NSEntityDescription entityForName:#"CHECKLIST"
inManagedObjectContext:ctx];
fetchRequest.predicate = [NSPredicate predicateWithFormat:
#"uniqueID in %#", importedIDs];
NSError *error = nil;
NSManagedObject *updatedObject;
NSArray *matchingItems;
matchingItems = [ctx executeFetchRequest:fetchRequest error:&error];
ImportedData *importedData;
for (int i = 0; i < [_importedRows count]; i++) {
importedData = [_importedRows objectAtIndex:i];
for (updatedObject in matchingItems) {
if ([importedData.uniqueID isEqualToString:[updatedObject valueForKey:#"uniqueID"]]) {
HUD.detailsLabelText = [NSString stringWithFormat:#"Updating %#" , [updatedObject valueForKey:#"figureName"]];
[updatedObject setValue:importedData.numberOwned forKey:#"numberOwned"];
[updatedObject setValue:importedData.numberWanted forKey:#"wishList"];
[updatedObject setValue:importedData.availableTrade forKey:#"tradeList"];
}
}
}
[ctx save:&error];
I'm sure it could still be a little cleaner and the actual updating portion (I'm not sure how to do it other than compare each item in the fetchedresults with each item in the initial array to make sure they are updated correctly, but the combined fetchedresults increased the speed tremendously (originally 240 seconds for 4000 items, now between 80-120 seconds)
sorting arrays first, then updating in order speeds it up tremendously yet again:
NSArray *matchingItemsSorted;
matchingItemsSorted = [matchingItems sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSString *first = [a valueForKey:#"uniqueID"];
NSString *second = [b valueForKey:#"uniqueID"];
return [first caseInsensitiveCompare:second];
}];
NSArray *importedRowsSorted;
importedRowsSorted = [_importedRows sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSString *first = [a valueForKeyPath:#"uniqueID"];
NSString *second = [b valueForKeyPath:#"uniqueID"];
return [first caseInsensitiveCompare:second];
}];
int i = 0;
for (updatedObject in matchingItemsSorted) {
NSLog(#"do we match? %# : %#", [[importedRowsSorted objectAtIndex:i] valueForKeyPath:#"uniqueID"], [updatedObject valueForKey:#"uniqueID"]);
HUD.detailsLabelText = [NSString stringWithFormat:#"Updating %#" , [updatedObject valueForKey:#"figureName"]];
[updatedObject setValue:[[importedRowsSorted objectAtIndex:i] valueForKeyPath:#"numberOwned"] forKey:#"numberOwned"];
[updatedObject setValue:[[importedRowsSorted objectAtIndex:i] valueForKeyPath:#"numberWanted"] forKey:#"wishList"];
[updatedObject setValue:[[importedRowsSorted objectAtIndex:i] valueForKeyPath:#"availableTrade"] forKey:#"tradeList"];
i++;
}
13 seconds or so for 4000 items with the nslog there... the only weird thing now is that when I comment out the nslog, it frequently crashes... is it happening so fast it's breaking core data - when it doesn't crash, it only takes about 4 seconds?
Thanks,
Zack
You have two nested loops. Use this pattern to speed this up:
NSArray *importedIDs = [_importedRows valueForKeyPath:#"uniqueID"];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
fetchRequest.entity = [NSEntityDescription entityForName:#"CHECKLIST"
inManagedObjectContext:ctx];
fetchRequest.predicate = [NSPredicate predicateWithFormat:
#"uniqueID in %#", importedIDs];
Like this you can fetch one array with all matching items.
I have a case where I should insert object into an entity via UIViewController. I have designed my database model (Entity and attributes). I'm adding the entity through a UIViewController. What am I supposed to add in the didFinishLaunchingwithOptions method in appDelegate.m?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch
return YES;
}
And for the TUTViewController (My own view controller - UIViewController) I have used the below code for inserting object.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
NSString *stripped1 = [response stringByReplacingOccurrencesOfString:#"\r" withString:#""];
NSMutableArray *rows = [NSMutableArray arrayWithArray:[stripped1 componentsSeparatedByString:#"\n"]];
NSMutableArray *contentArray = [NSMutableArray arrayWithCapacity:[rows count]];
NSMutableArray *contentArray1 = [NSMutableArray arrayWithCapacity:[rows count]];
NSArray *components;
NSLog(#"count:%d",[rows count]);
for (int i=0;i<[rows count]; i++) {
if(i == 0 || [[rows objectAtIndex:i] isEqualToString:#""]){
continue;
}
components = [[rows objectAtIndex:i] componentsSeparatedByString:#","];
id x = [components objectAtIndex:0] ;
id y = [components objectAtIndex:1];
id z = [components objectAtIndex:2];
[contentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x,#"X",y,#"Y", nil]];
[contentArray1 addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x,#"X",z,#"Y", nil]];
[newManagedObject setValue:[x] forKey:#"timeStamp"];
[newManagedObject setValue:[y] forKey:#"beat"];
[newManagedObject setValue:[z] forKey:#"rate"];
// Save the context.
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
NSLog(#"Contents of Uterus Contraction: %#",contentArray);
NSLog(#"Contents of Heart Beat: %#",contentArray1);
}
}
}
Is there anything that I'm missing? I'm ending up with the error:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: '+entityForName: could not
locate an NSManagedObjectModel for entity name 'FetalData''
Did you set up the Core Data Stack or a UIManagedDocument object?
If you didn't set up the Managed Object Model this could be the problem. It means you're probably not loading Managed Object Model that defines FetalData entity. See insertnewobjectforentityforname for further info.
I really suggest to create an empty project and let Xcode to create Core Data stuff for you. In this manner you can see how the code works.
Some Notes
Why do you use a NSFetchResultsController?
Move the save call at the end of your method. In this manner you avoid multiple round trips to the disk.
If you want to start using Core Data, I suggest you core-data-on-ios-5-tutorial-getting-started.
Hope it helps.