2017-07-24 50 views
0

我在一个已发布的应用程序中偶然发生崩溃,并从崩溃报告知道它发生在哪一行以及崩溃类型 - EXC_BAD_ACCESS(SIGSEGV)KERN_INVALID_ADDRESS - 但我不知道如何内存可能会变得无效,因为被引用的对象的生命周期是应用程序的生命周期,并且除非应用程序终止,否则不会被删除。因此,如果崩溃不是由于访问已删除的内存造成的(因为该内存未被删除),在这种特殊情况下EXC_BAD_ACCESS会有什么其他原因?EXC_BAD_ACCESS KERN_INVALID_ADDRESS但内存未被删除

下面的代码:

@interface Model() 
@property (strong, nonatomic) NSMutableDictionary* cityAndStateDictionary; 
@end 


- (NSString*) findAddress: (NSString*) key 
{ 
    if (key == nil) 
    { 
     return nil; 
    } 
    NSString* cityAndState = (self.cityAndStateDictionary)[key]; // Crash here 
} 



@implementation Model 
- (id) init 
{ 
    self = [super init]; 
    if (self) 
    { 
     dispatch_async(modelQueue(), ^{ 
      [self readCityAndStateData]; 
     }); 
    } 
} 


- (void) readCityAndStateData 
{ 
    NSBundle* bundle = [NSBundle bundleForClass:[Model class]]; 
    NSString *filePath = [bundle pathForResource:@"CityState" ofType:@"json"]; 
    NSData *data = [NSData dataWithContentsOfFile:filePath]; 
    NSError* __autoreleasing nserror; 
    NSDictionary* jsonParser = [NSJSONSerialization JSONObjectWithData: data 
                   options: NSJSONReadingAllowFragments 
                   error: &nserror]; 
    if (nserror == nil) 
    { 
     self.cityAndStateDictionary = [[NSMutableDictionary alloc] init]; 
     for (NSDictionary *item in jsonParser) 
     { 
      // create value object 
      (self.cityAndStateDictionary)[key] = value; 
     } 
    } 
} 

readCityAndStateData()正在创建一个线程内填充,如果findAddress()已完成之前被称为然后cityAndStateDictionary将是零,所以在findAddress调用(self.cityAndStateDictionary)[key]也只是零。 cityAndStateDictionary对象是而不是被删除的任何地方,因此崩溃不应该由于访问已删除的内存。

坠机的原因是什么?

Exception Type: EXC_BAD_ACCESS (SIGSEGV) 
Exception Subtype: KERN_INVALID_ADDRESS at 0x000000010624ae60 
Termination Signal: Segmentation fault: 11 
Termination Reason: Namespace SIGNAL, Code 0xb 
Terminating Process: exc handler [0] 
Triggered by Thread: 0 

Thread 0 name: 
Thread 0 Crashed: 
0 CoreFoundation     0x000000018356446c -[__NSDictionaryM objectForKey:] + 108 (NSDictionary.m:543) 
1 CoreFoundation     0x0000000183564450 -[__NSDictionaryM objectForKey:] + 80 (NSDictionary.m:538) 
2 Name Of May App     0x0000000100021f38 -[Model findAddress:] + 268 (Model.m:590) 
3 Name Of May App     0x00000001000beb78 _TTSf4g_n_n___TFC14Caller_Name_ID28BlockedNumbersViewController17formatBlockedCellfT6callerCS_6Caller3rowSi_CS_11BlockedCell + 1688 (BlockedNumbersViewController.swift:395) 
4 Name Of May App     0x00000001000bf1b0 _TTSf4g_g_n___TFC14Caller_Name_ID28BlockedNumbersViewController9tableViewfTCSo11UITableView12cellForRowAtV10Foundation9IndexPath_CSo15UITableViewCell + 528 (BlockedNumbersViewController.swift:0) 
5 Name Of May App     0x00000001000ba01c _TToFC14Caller_Name_ID28BlockedNumbersViewController9tableViewfTCSo11UITableView12cellForRowAtV10Foundation9IndexPath_CSo15UITableViewCell + 76 (BlockedNumbersViewController.swift:0) 
6 UIKit       0x0000000189af5aa8 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 688 (UITableView.m:10803) 
7 UIKit       0x0000000189af5cc0 -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 80 (UITableView.m:10848) 
8 UIKit       0x0000000189ae33c4 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2152 (UITableView.m:2273) 
9 UIKit       0x0000000189afacb0 -[UITableView _performWithCachedTraitCollection:] + 120 (UITableView.m:12556) 
10 UIKit       0x0000000189893774 -[UITableView layoutSubviews] + 176 (UITableView.m:7390) 
11 UIKit       0x00000001897adf98 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1200 (UIView.m:14232) 
12 QuartzCore      0x000000018699e274 -[CALayer layoutSublayers] + 148 (CALayer.mm:8937) 
13 QuartzCore      0x0000000186992de8 CA::Layer::layout_if_needed(CA::Transaction*) + 292 (CALayer.mm:8817) 
14 QuartzCore      0x0000000186992ca8 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 32 (CALayer.mm:2345) 
15 QuartzCore      0x000000018690e34c CA::Context::commit_transaction(CA::Transaction*) + 252 (CAContextInternal.mm:1689) 
16 QuartzCore      0x00000001869353ac CA::Transaction::commit() + 504 (CATransactionInternal.mm:420) 
17 QuartzCore      0x0000000186935e78 CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 120 (CATransactionInternal.mm:793) 
18 CoreFoundation     0x000000018362c9a8 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32 (CFRunLoop.c:1802) 
19 CoreFoundation     0x000000018362a630 __CFRunLoopDoObservers + 372 (CFRunLoop.c:1898) 
20 CoreFoundation     0x000000018362aa7c __CFRunLoopRun + 956 (CFRunLoop.c:2849) 
21 CoreFoundation     0x000000018355ada4 CFRunLoopRunSpecific + 424 (CFRunLoop.c:3113) 
22 GraphicsServices    0x0000000184fc5074 GSEventRunModal + 100 (GSEvent.c:2245) 
23 UIKit       0x0000000189815f74 UIApplicationMain + 208 (UIApplication.m:4089) 
24 Name Of May App     0x000000010003a8b4 main + 56 (Database.swift:17) 
25 libdyld.dylib     0x000000018256959c start + 4 
+0

我想和一个并发调用的问题......在'-init'中做一个异步调用,我不认为这是建议的。相反,我会在'findAddress'上创建一个块,并且像我们在UITableView中加载图像一样。 – Larme

+0

在init中启动异步进程不是问题;它经常用于昂贵的初始化过程。但是,您确定这很可能是并发问题。 – bbum

回答

0

可变字典不是线程安全的。

您需要确保字典只能从单个线程访问。

请注意dispatch_asyncinit不是问题。但在这种情况下不太可能需要。您是否测量了readCityAndStates方法的执行时间,以确定它是否确实是性能问题?另外,不要将该静态资源存储为JSON,而应将其存储为二进制格式。这将解析得更快,而且更重要的是,可以缩减应用程序包的大小。

+0

字典可能需要2或3秒才能填充。确保只能从单个线程访问的最佳方式是什么? – Gruntcakes

+0

首先,转向使用二进制存储格式。 NSArchiver应该做的伎俩。我敢打赌,这将足够快。接下来,该字典应该只填充一次,因为根据定义,应用程序主包中的资源不能更改。如果二进制格式的速度不够快,那么只有这样,才能考虑如何使线程安全。 – bbum