Why app crashing while set a value to NSManagedObject in ios - ios

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....

Related

iOS - Shuffle/Randomize order of objects in NSMutableArray

I want to shuffle/randomize the order of the items inside my NSMutableArray when method reloadData is executed. I tried the below, but console keeps throwing me the following error:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSArrayI
exchangeObjectAtIndex:withObjectAtIndex:]: unrecognized selector sent
to instance 0x1748b2c60'
Any idea why this might be? I'm stumped.
ViewController.h
#property (strong, retain) NSMutableArray *neighbourData;
ViewController.m
- (void)reloadData:(id)sender
{
NSMutableDictionary *viewParams = [NSMutableDictionary new];
[viewParams setValue:#"u000" forKey:#"view_name"];
[DIOSView viewGet:viewParams success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.neighbourData = (NSMutableArray *)responseObject;
[self.tableView reloadData];
NSUInteger count = [self.neighbourData count];
for (NSUInteger i = 0; i < count; ++i) {
// Select a random element between i and end of array to swap with.
int nElements = count - i;
int n = (arc4random() % nElements) + i;
[self.neighbourData exchangeObjectAtIndex:i withObjectAtIndex:n];
}
NSLog(#"This is the neighbourdata %#",self.neighbourData);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
The error indicates that responseObject is actually a non-mutable NSArray. The cast you applied simply lies to the compiler but it doesn't actually change anything at runtime.
Change:
self.neighbourData = (NSMutableArray *)responseObject;
to:
self.neighbourData = [(NSArray *)responseObject mutableCopy];
For production you really ought to use the built in Fisher-Yates shuffle in Gamekit. If you are doing this for leaning purposes then the problem is in the line:
int n = (arc4random() % nElements) + i;
You are making a random number from the first to the last element and then you are adding i to it. Clearly this means that your index can now be out of bounds. Get rid of the + i.
self.neighbourData = (NSMutableArray *)responseObject;
You have to make sure that your responseObject is an instance of NSMutableArray here. Even though you cast the type responseObject to NSMutableArray, it will crash if it's not an instance of NSMutableArray because it dose not have a exchangeObjectAtIndex:withObjectAtIndex:. In this case your responseObject is a NSArray instance, your could change the code to:
NSArray *tmp = (NSArray *)responseObject;
self.neighbourData = [tmp mutableCopy];
I think this works for you.

app crashes on fast uisearchbar text entry

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"]];
}

iOS replaceObjectAtIndex Error

I am new to iOS development, I encounter error when replaceObjectAtIndex. Any wrong with my codes? Please help.Thanks.
self.myArray =array;
for (NSDictionary *data in array) {
NSString *fbid = [data objectForKey:#"id"];
for (int index = 0; index < self.myPersonArray.count; index ++) {
for (IP_PERSON *person in self.myPersonArray) {
if ([person.UserDef2 isEqualToString:fbid]) {
[self.myArray replaceObjectAtIndex:index withObject:person];
break;
}
}
}
Error is :
Terminating app due to uncaught exception NSGenericException, reason: '*** Collection <__NSArrayM: 0xa34f6c0> was mutated while being enumerated.
You cannot use fast enumeration and mutate collection at the same time, hence the error message. You can resort to using an usual for-loop.
You're iterating over array, which is equal to self.myArray.
Further down, you're editing this array when you do: [self.myArray replaceObjectAtIndex:index withObject:person];
To resolve this, just make self.array a mutableCopy of the original array:
self.myArray = [array mutableCopy];
You can take another temporary array and iterate over that array, so you are enumerating and mutating different array.
NSArray *tempArray = [yourArray copy];
for (IP_PERSON *person in tempArray) {
if ([person.UserDef2 isEqualToString:fbid]) {
[self.myArray replaceObjectAtIndex:index withObject:person];
break;
}
}
[tempArray release];
Alternatively you can iterate without an enumerator, you can use regular for loop with starting index, exit condition and increment as you have done in outer loop.
You can..
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]
self.myArray =array;
for (NSDictionary *data in array) {
NSString *fbid = [data objectForKey:#"id"];
for (int index = 0; index < self.myPersonArray.count; index ++) {
for (IP_PERSON *person in self.myPersonArray) {
if ([person.UserDef2 isEqualToString:fbid]) {
[dictionary setObject:person forKey:#(index)]; //Notice this line
break;
}
}
}
}
And then..
for(id key in dictionary) {
[self.myArray replaceObjectAtIndex:[key intValue] withObject:[dictionary objectForKey:key]];
}

Adding data to an entity through a view controller

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.

iOS: Core data error: NSMergeConflict for NSManagedObject

I have a core data many to many relationship of article to category. When attempting to save, I get the following error. I am unable to find information about what it means, and why there are two versions when the database is empty. Can anyone shed some light?
Error: NSMergeConflict (0x76ae720) for NSManagedObject (0xd945560) with objectID '0xd943550 <x-coredata://09A438A8-E3F5-45FE-B9D7-106798E82E18/Article/p91>' with oldVersion = 1 and newVersion = 2
Code:
NSMutableDictionary *dict = [[data objectAtIndex:i] valueForKey:#"category_names"];
NSMutableArray *values = [[NSMutableArray alloc] init];
for (NSString *value in [dict allValues]) {
NSLog(#"value = %#", value);
[values addObject:value];
}
NSMutableSet *setElements = [[NSMutableSet alloc] init];
for (int i = 0; i < [values count]; i++) {
Category *cat = [self getCategoryFor:[values objectAtIndex:i]]; // Function which has fetch to get the category for the value "name"
[setElements addObject:cat];
}
if ([setElements count] > 0)
[article addCategories:setElements];
// Save the context.
NSError* error;
if (![managedObjectContext save:&error]) {
NSLog(#"Failed to save to data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0) {
for(NSError* detailedError in detailedErrors) {
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
} else
NSLog(#" %#", [error userInfo]);
}
[article release];
[values release];
[setElements release];
The error your getting is not actually related to the data itself but rather caused by having two irreconcilable versions of the data model writing to the same persistent store file.
You must have created a data model, used it write some data to the persistent store and then updated the model. This is normally not an issue unless you so alter the data model that the automatic migration cannot merge the old and new data.
If this is still under development and you don't need the existing data, the easiest solution is to delete the app off the simulator and then build and run it again using only the latest data model. That will require no migration and will therefore skip the merge error.

Resources