La investigación de un informe de locking de iOS con EXC_BAD_ACCESS (SIGSEGV) y con ARM Thread State (64 bits)

Recientemente he publicado una actualización de mi aplicación en App Store. La testing no causó fallas, pero noté que cuando se lanzó en la App Store, ese escenario bloqueó mi aplicación en mis 5s. Este escenario no se bloqueó durante el desarrollo. Recibí un informe de un usuario que decía que también se había estrellado en un escenario en sus 5s, que es lo mismo que estaba haciendo.

Estoy en una etapa intermedia del desarrollo de iOS y esta es mi primera experiencia con el diagnóstico de un informe de falla.

Actualización: avance a la parte inferior de las preguntas para get más información sobre los problemas.

Dentro de Xcode, tengo el siguiente informe de locking para mi aplicación en mis 5s:

Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000060 Triggenetworking by Thread: 0 Thread 0 Crashed: 0 CoreData 0x00000001822f8af4 _propertyAtIndexForEntityDescription + 24 1 CoreData 0x00000001822f0330 snapshot_get_value_as_object + 304 2 Foundation 0x0000000183080a78 -[NSObject(NSKeyValueCoding) valueForKeyPath:] + 288 3 Foundation 0x00000001831613cc -[NSSortDescriptor compareObject:toObject:] + 140 4 CoreData 0x0000000182305d9c +[NSFetchedResultsController(PrivateMethods) _insertIndexForObject:inArray:lowIdx:highIdx:sortDescriptors:] + 284 5 CoreData 0x00000001823dd808 -[NSFetchedResultsController(PrivateMethods) _createNewSectionForObject:] + 492 6 CoreData 0x0000000182305b58 -[NSFetchedResultsController(PrivateMethods) _postprocessInsertedObjects:] + 528 7 CoreData 0x00000001823025f8 -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] + 2036 8 CoreFoundation 0x000000018259b760 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 16 9 CoreFoundation 0x00000001824e82b0 _CFXNotificationPost + 2060 10 Foundation 0x000000018307a744 -[NSNotificationCenter postNotificationName:object:userInfo:] + 68 11 CoreData 0x0000000182301dd8 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 84 12 CoreData 0x0000000182301d58 -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:] + 360 13 CoreData 0x0000000182300348 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 2224 14 CoreData 0x00000001822ff264 -[NSManagedObjectContext save:] + 152 15 Lopey 0x000000010004da3c -[LopeyAddEntryViewController save:] (LopeyAddEntryViewController.m:828) 16 UIKit 0x00000001855e50ac -[UIApplication sendAction:to:from:forEvent:] + 96 17 UIKit 0x00000001855e50ac -[UIApplication sendAction:to:from:forEvent:] + 96 18 UIKit 0x00000001855e5040 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 20 19 UIKit 0x00000001855ce51c -[UIControl _sendActionsForEvents:withEvent:] + 372 20 UIKit 0x00000001855e4a40 -[UIControl touchesEnded:withEvent:] + 580 21 UIKit 0x00000001855e46d4 -[UIWindow _sendTouchesForEvent:] + 688 22 UIKit 0x00000001855df36c -[UIWindow sendEvent:] + 1168 23 UIKit 0x00000001855b0b4c -[UIApplication sendEvent:] + 252 24 UIKit 0x00000001855aec3c _UIApplicationHandleEventQueue + 8496 25 CoreFoundation 0x00000001825a77f0 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 20 26 CoreFoundation 0x00000001825a6b4c __CFRunLoopDoSources0 + 252 27 CoreFoundation 0x00000001825a4de4 __CFRunLoopRun + 628 28 CoreFoundation 0x00000001824e5dcc CFRunLoopRunSpecific + 448 29 GraphicsServices 0x00000001881cdc08 GSEventRunModal + 164 30 UIKit 0x0000000185616fc0 UIApplicationMain + 1152 31 Lopey 0x000000010005a40c main (main.m:16) 32 libdyld.dylib 0x000000018f0e3a9c start + 0 

También tengo un poco más abajo:

 Thread 0 crashed with ARM Thread State (64-bit): x0: 0x0000000000000000 x1: 0x0000000000000000 x2: 0x0000000000000000 x3: 0x0000000000000000 x4: 0x0000000000000001 x5: 0x0000000000000074 x6: 0x0000000000000074 x7: 0x0000000000000000 x8: 0x0000000000000060 x9: 0x0000000000000020 x10: 0x0000000100124540 x11: 0x000000100000001f x12: 0x00000001001245a0 x13: 0x0000000178242d60 x14: 0x0000000000000034 x15: 0x0000000004060401 x16: 0x000000018a1c96e6 x17: 0x000000018234e2d4 x18: 0x0000000000000000 x19: 0x0000000000000000 x20: 0x000000017043b580 x21: 0x0000000000000011 x22: 0x000000017043c1e0 x23: 0x0000000000000006 x24: 0x000000018265d35b x25: 0x000000018f715000 x26: 0x000000018f715000 x27: 0x0000000000000002 x28: 0x00000001780dbd60 fp: 0x000000016fdfc850 lr: 0x00000001822f0334 sp: 0x000000016fdfc840 pc: 0x00000001822f8af4 cpsr: 0x60000000 

Como se puede ver en los loggings, estoy usando Core Data con NSFetchedResultsController . Tengo un UITableViewController que se completa como resultado de que el usuario click un button en UINavigationBar , agregando algunas inputs en unos pocos UITextField sy presionando "Guardar". Ese es el punto en que se estrelló. Sin embargo, debo mencionar que no se cuelga cada vez. De hecho, antes del crash, había agregado 45 inputs consecutivas y después de eso, agregué 100 sin lockings. Solo ha sucedido una vez.

El punto en la aplicación donde se bloquea es cuando UITableView Guardar (que descartará ViewController y volverá a UITableView . Con esto en mente, es el "guardado" real de NSManagedObjectContext , o es la carga de la UITableView. Mi dinero está en el primero, pero no estoy realmente seguro.

Aquí está mi código para el NSManagedObjectContext en el App Delegate la App Delegate :

 - (NSManagedObjectContext *)managedObjectContext { if (_managedObjectContext != nil) { return _managedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; moc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy; [moc setPersistentStoreCoordinator: coordinator]; _managedObjectContext = moc; } return _managedObjectContext; } 

Aquí está mi método Save en el App Delegate la App Delegate :

 - (void)saveContext { NSError *error = nil; NSManagedObjectContext *managedObjectContext = self.managedObjectContext; if (managedObjectContext != nil) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { // Replace this implementation with code to handle the error appropriately. // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. //NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } } 

Como se mencionó, soy bastante nuevo en el desarrollo y esta es la primera vez que veo un logging de locking que necesita ser investigado. Cualquier dirección en esto sería realmente apreciada. ¿También es algo relacionado con el procesador de 64 bits en los 5? (Quizás esto explicaría por qué no puedo reproducirlo en otra parte).

Actualización 1

Mi aplicación es solo iOS 7. My 5s es solo iOS 7 y he probado mi aplicación en iOS 8, pero con 4 años y no he experimentado lockings similares. Además, he probado también en un iPad Mini, así que este es un problema solo para iPhone 5s.

Actualización 2

Mostrando el código que guarda los nuevos objects a continuación. Puede parecer complicado, pero esencialmente el nombre, el evento, etc. se basa en la autocompletación, que se basa en qué objects ya se encuentran en Datos básicos, etc.

 - (IBAction)save:(id)sender { NSManagedObjectContext *context = [self managedObjectContext]; // Insert a new transaction Transaction *transaction = [NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:context]; Item *itemType = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:context]; itemType.amount = self.itemTextField.text; transaction.item = itemType; transaction.wasReceived = @(self.isReceivedSegment.selectedSegmentIndex == 0); Person *entenetworkingPerson = (Person *)[Person personWithName:self.nameTextField.text inManagedObjectContext:context]; transaction.whoBy = entenetworkingPerson; Occasion *entenetworkingOccasion = (Occasion *)[Occasion occasionWithTitle:self.occasionTextField.text inManagedObjectContext:context]; transaction.occasion = entenetworkingOccasion; Subevent *entenetworkingSubevent = (Subevent *)[Subevent subeventWithTitle:self.subeventTextField.text inManagedObjectContext:context]; transaction.subevent = entenetworkingSubevent; NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *components = [cal components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:self.datePicker.date]; [components setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; NSDate *selectedDate = [cal dateFromComponents:components]; Date *date = (Date *)[Date occasionWithDate:selectedDate inManagedObjectContext:context]; transaction.dates = date; NSError *error = nil; if (![context save:&error]) { // Error } [self dismissViewControllerAnimated:YES completion:nil]; } 

Dentro de UITableViewController, mi fetchedResultsController se encuentra a continuación:

 - (NSFetchedResultsController *)fetchedResultsController { NSManagedObjectContext *managedObjectContext = [self managedObjectContext]; if (_fetchedResultsController != nil) { return _fetchedResultsController; } NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Transaction" inManagedObjectContext:managedObjectContext]; fetchRequest.entity = entity; // I am implementing a search here so we can either search by name or event with the pnetworkingiate filtering out the information. if ([self.timelineSearchBar.text length] > 0) { NSPnetworkingicate *pnetworkingName = [NSPnetworkingicate pnetworkingicateWithFormat:@"whoBy.name CONTAINS[c] %@", self.timelineSearchBar.text]; NSPnetworkingicate *pnetworkingOccasion = [NSPnetworkingicate pnetworkingicateWithFormat:@"occasion.title CONTAINS[c] %@", self.timelineSearchBar.text]; // Adding in another pnetworkingicate for searching by subevent NSPnetworkingicate *pnetworkingSubOccasion = [NSPnetworkingicate pnetworkingicateWithFormat:@"subevent.title CONTAINS[c] %@", self.timelineSearchBar.text]; // creating the orCompoundPnetworkingicate for the two conditions NSPnetworkingicate *compPnetworkingicate = [NSCompoundPnetworkingicate orPnetworkingicateWithSubpnetworkingicates:@[pnetworkingName, pnetworkingOccasion, pnetworkingSubOccasion]]; [fetchRequest setPnetworkingicate:compPnetworkingicate]; } // Sorting by date and by name. NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"dates.dateOfEvent" ascending:NO]; NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"whoBy.name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)]; fetchRequest.sortDescriptors = @[sort, sortDescriptor]; fetchRequest.fetchBatchSize = 20; NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"sectionDateFormatter" cacheName:nil]; self.fetchedResultsController = theFetchedResultsController; _fetchedResultsController.delegate = self; return _fetchedResultsController; } 

Espero que esto sea útil!

Actualización 3

Quería intentar reproducir el problema. Los pasos para reproducir la primera vez implicaron la actualización desde una versión anterior de la aplicación. Tenía la versión de App Store en mi dispositivo antes de la actualización, y cuando se lanzó la actualización, la actualicé, creó una nueva input y ese es el punto en que se estrelló. Corrí la versión anterior de mi aplicación y la actualicé a esta nueva versión en Xcode y, cuando la aplicación se actualizó y estaba list, añadí una nueva input y con un punto de interrupción de exception, se bloqueó en transaction.dates = date ; en el método Save enumerado anteriormente, en la actualización 2. El punto de interrupción estaba informando: Thread 1: EXC_BAD_ACCESS (code=1,address=0x60) .

Realicé los pasos nuevamente, sin el punto de interrupción y se detuvo en la misma línea de código con el mismo error.

Actualización 4

Este locking solo ocurre si actualizo mi aplicación a la última versión y agrego una nueva input de inmediato. Sin embargo, si vuelvo a ejecutar la aplicación antes de agregar una nueva input, el dispositivo no se bloquea.

Actualización 5

Con algunas testings adicionales, he descubierto que este locking es el resultado de la actualización a esta nueva versión en un iPhone 5s y un iPad Air solamente. La aplicación no falla en ningún otro dispositivo. Con esta última versión de la aplicación, he traído sincronizaciones de iCloud. En el App Delegate la App Delegate , tengo el código a continuación que se ejecutará cuando el usuario elija seleccionar usar iCloud en el tutorial de la actualización. Es con este escenario que la aplicación se bloquea.

 - (void)initialMigrationOfLocalDataToiCloud { NSURL *storeURL = [self.persistentStoreCoordinator.persistentStores.lastObject URL]; NSPersistentStore *currentStore = self.persistentStoreCoordinator.persistentStores.lastObject; NSURL *cloudURL = [self grabCloudPath:@"CloudLogs"]; NSString *cloudStoreTitle = @"LopeyCloud"; NSDictionary *options = @{NSPersistentStoreUbiquitousContentURLKey: cloudURL, NSPersistentStoreUbiquitousContentNameKey: cloudStoreTitle, NSMigratePersistentStoresAutomaticallyOption : @YES, NSInferMappingModelAutomaticallyOption : @YES}; [self.persistentStoreCoordinator migratePersistentStore:currentStore toURL:storeURL options:options withType:NSSQLiteStoreType error:nil]; } 

Tengo la migration ligera allí porque el usuario puede estar actualizando desde una versión anterior, etc.

Con un set de punto de interrupción de exception (e incluso sin él), la aplicación se bloqueará en la transaction.dates = date; código en el método save , según la Actualización 2 . No puedo saltar del código ni hacer nada con esto. Al recorrer el depurador, no puedo ver cuál es el valor de transaction.dates , pero la date no es nula. Incluso si no establezco un punto de interrupción, la aplicación se bloqueará en la misma línea de código aquí.

Espero que esto tenga sentido.