我最近在App Store中发布了对我应用的更新。测试没有发生崩溃,但我注意到它在App Store中发布时,一个场景在我的5s上崩溃了我的应用程序。这种情况在开发过程中没有崩溃。我收到了一个用户的报告,说它在5s的一个场景中也崩溃了,这跟我正在做的一样。
我正处于iOS开发的中间阶段,这是我诊断崩溃报告的第一次经历。
更新:请滚动到问题的底部以获取有关问题的进一步更新
在Xcode中,我的5s上的应用程序有以下崩溃报告:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000060
Triggered 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
我还有一点下来:
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
从日志中可以看出,我正在Core Data
使用NSFetchedResultsController
。我有一个UITableViewController
因用户点击UINavigationBar
中的按钮而被填充,将一些条目添加到几个UITextField
并按“保存”。这就是崩溃的一点。但是,我必须提到它每次都不会崩溃。实际上,在崩溃之前,我已经连续添加了45个条目,之后我添加了100个没有崩溃。它只发生过一次。
应用程序中崩溃的点是我按下保存(这将关闭ViewController
并返回UITableView
。考虑到这一点,它要么是实际的“保存” “NSManagedObjectContext
中的,或者是UITableView的加载。我的钱是前者,但我不太确定。
以下是NSManagedObjectContext
中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;
}
以下是Save
中的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();
}
}
}
如上所述,我对开发还很陌生,这是我第一次看到需要调查的崩溃日志。这方面的任何方向都会受到赞赏。它是否也与5s中的64位处理器有关? (也许这可以解释为什么我不能在其他地方重现它?)。
更新1
我的应用仅限iOS 7。我的5s只是iOS 7,我已经在iOS 8上测试了我的应用程序,但是在4s上没有遇到类似的崩溃。此外,我也在iPad Mini上测试过,所以这只是iPhone 5s的问题。
更新2
显示保存下面新对象的代码。它可能看起来很复杂,但基本上名称,事件等基于自动完成,该自动完成基于哪些对象已经存在于核心数据中等。
- (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 *enteredPerson = (Person *)[Person personWithName:self.nameTextField.text inManagedObjectContext:context];
transaction.whoBy = enteredPerson;
Occasion *enteredOccasion = (Occasion *)[Occasion occasionWithTitle:self.occasionTextField.text inManagedObjectContext:context];
transaction.occasion = enteredOccasion;
Subevent *enteredSubevent = (Subevent *)[Subevent subeventWithTitle:self.subeventTextField.text inManagedObjectContext:context];
transaction.subevent = enteredSubevent;
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];
}
在UITableViewController中,我的fetchedResultsController位于:
- (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 prediate filtering out the information.
if ([self.timelineSearchBar.text length] > 0) {
NSPredicate *predName = [NSPredicate predicateWithFormat:@"whoBy.name CONTAINS[c] %@", self.timelineSearchBar.text];
NSPredicate *predOccasion = [NSPredicate predicateWithFormat:@"occasion.title CONTAINS[c] %@", self.timelineSearchBar.text];
// Adding in another predicate for searching by subevent
NSPredicate *predSubOccasion = [NSPredicate predicateWithFormat:@"subevent.title CONTAINS[c] %@", self.timelineSearchBar.text];
// creating the orCompoundPredicate for the two conditions
NSPredicate *compPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predName, predOccasion, predSubOccasion]];
[fetchRequest setPredicate:compPredicate];
}
// 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;
}
希望这有用!
更新3
我想尝试重现这个问题。第一次重现的步骤涉及从先前版本的应用程序进行更新。在更新之前,我的设备上有App Store版本,当更新发布时,我更新到了那个,创建了一个新条目,这就是它崩溃的一点。我运行了我的应用程序的旧版本,并在Xcode中升级到这个新版本,当应用程序升级并准备好时,我添加了一个新条目和一个异常断点,它在transaction.dates = date
崩溃了;在上面列出的Save方法中,在更新2中。断点报告:Thread 1: EXC_BAD_ACCESS (code=1,address=0x60)
。
我再次执行了这些步骤,没有断点,并且在相同的代码行停止并出现相同的错误。
更新4
如果我将应用更新到最新版本并立即添加新条目,则只会发生此崩溃。但是,如果我在添加新条目之前重新运行应用程序,则设备不会崩溃。
更新5
通过一些进一步的测试,我发现这次崩溃是因为只在iPhone 5s和iPad Air上更新到这个新版本。该应用程序不会在任何其他设备上崩溃。有了这个最新版本的应用程序,我带来了iCloud同步。在App Delegate
中,我在下面的代码将在用户选择在更新教程中选择使用iCloud时运行。正是在这种情况下,应用程序崩溃了。
- (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];
}
我在那里进行了轻量级迁移,因为用户可能正在从以前的版本等进行更新。
设置了异常断点(即使没有它),根据 Update 2 ,应用会在transaction.dates = date;
方法的save
代码中崩溃。我不允许跳出代码或对此做任何事情。通过调试器,我看不出transaction.dates
的值是什么,但date
不是零。即使我没有设置断点,应用程序也会在此处的同一行代码中崩溃。
我希望这是有道理的。