2017-07-24 5 views
0

Ich habe gelegentlich einen Absturz in einer freigegebenen App und von Absturzberichten wissen, die Zeile bei Auftreten und Art des Absturzes - EXC_BAD_ACCESS (SIGSEGV) KERN_INVALID_ADDRESS - aber ich weiß nicht wie Der Speicher könnte ungültig werden, da die Lebensdauer des Objekts, auf das verwiesen wird, die Lebensdauer der App ist und nicht gelöscht wird, wenn die App nicht beendet wird. Wenn also der Absturz nicht auf den gelöschten Speicher zurückzuführen ist (weil dieser Speicher nicht gelöscht wird), welche anderen Gründe könnte es für die EXC_BAD_ACCESS in dieser speziellen Situation geben?EXC_BAD_ACCESS KERN_INVALID_ADDRESS aber Speicher wird nicht gelöscht

Hier ist der Code:

@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() in einem Thread erstellt und aufgefüllt wird und wenn findAddress() aufgerufen wird, bevor das dann gleich Null und nur Null sein würde, so der Aufruf von (self.cityAndStateDictionary)[key] in Findaddress wäre cityAndStateDictionary abgeschlossen . Das cityAndStateDictionary Objekt ist nicht wird überall gelöscht, daher sollte der Absturz nicht auf den Zugriff auf gelöschten Speicher zurückzuführen sein.

Welchen Grund könnte es für den Absturz geben?

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

Ich würde mit einem Problem von gleichzeitigen Anrufen gehen ... Einen Async-Aufruf in der "-init", ich glaube nicht, dass das empfohlen wird. Ich würde stattdessen einen Block auf "findAddress" erstellen und dasselbe machen, wie wir das Bild in UITableView laden. – Larme

+0

Es ist kein Problem, einen asynchronen Prozess in einer 'init' zu starten; es ist oft für teure Initialisierungsprozesse getan. Sie haben jedoch Recht, dass dies höchstwahrscheinlich ein Nebenläufigkeitsproblem ist. – bbum

Antwort

0

Veränderbare Wörterbücher sind nicht Thread-sicher.

Sie müssen sicherstellen, dass auf das Wörterbuch nur über einen einzelnen Thread zugegriffen wird.

Beachten Sie, dass dispatch_async von init kein Problem ist. Aber es ist unwahrscheinlich, dass es in diesem Fall notwendig ist. Haben Sie die Ausführungszeit Ihrer readCityAndStates-Methode gemessen, um festzustellen, ob es sich tatsächlich um ein Leistungsproblem handelt? Anstatt diese statische Ressource als JSON zu speichern, sollten Sie sie auch in einem Binärformat speichern. Das wird viel schneller parsen und vor allem die Größe Ihres App-Bundles verringern.

+0

Es kann 2 oder 3 Sekunden dauern, bis das Wörterbuch gefüllt ist. Was ist der beste Weg, um sicherzustellen, dass nur von einem einzigen Thread zugegriffen wird? – Gruntcakes

+0

Wechseln Sie zunächst zu einem binären Speicherformat. NSArchiver sollte den Trick machen. Ich wette, das wird schnell genug sein. Als Nächstes sollte dieses Wörterbuch nur einmal ausgefüllt werden, da per Definition eine Ressource aus dem Hauptpaket der App nicht geändert werden kann. Wenn das Binärformat nicht schnell genug ist, dann sollten Sie überlegen, wie Sie es threadsicher machen können. – bbum

Verwandte Themen