I have a case where I get an exception EXC_BAD_ACCESS (code=1, address=0x4)at random when calling a method with multiple threads. The same method, once cheated on mistakes, sometimes not. But my measurements show that at least 1 out of 5 runs will produce this error.
First, let me show you a diagram of how my code is organized, so it will be easier to read the code.

View, (, AppDelegate) . CompleteHandler, .
, ViewControllers.
ViewController , .
, , .
, ViewController, .
, , , - .
Zombies, .
:
ViewController
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(modelProgressUpdate:) name:ProcessUpdateNotification object:nil];
self.coreDataQueue = dispatch_queue_create("com.my.core.data", NULL);
[self download1];
}
#pragma mark - Progres bar
- (void) modelProgressUpdate:(NSNotification * ) notification{
BINotificationsProcessUpdate * update = (BINotificationsProcessUpdate * )notification.object;
[self updateProgressWithPercent:update.percent];
}
- (void) modelPrograssCancel
{
[self.progressViewContainer layoutSubviews];
[UIView animateWithDuration:0.5 animations:^{
self.ProgressViewTopConstraint.constant = -15;
[self.progressViewContainer layoutSubviews];
[self.view layoutSubviews];
}];
self.ProgressView.progress = 0;
}
- (void) cancelProgresView
{
[self modelPrograssCancel];
}
- (void) progressInProcentage1:(float)procentage{
__weak ViewController * weekSelf = self;
dispatch_async(dispatch_get_main_queue(), ^(void) {
[weekSelf updateProgressWithPercent:procentage];
});
}
- (void) progressInProcentage2:(float)procentage{
__weak ViewController * weekSelf = self;
dispatch_async(dispatch_get_main_queue(), ^(void) {
[weekSelf updateProgressWithPercent:procentage];
});
}
- (void) updateProgressWithPercent: (float) percent
{
if (self.ProgressViewTopConstraint.constant != 0) {
[self.progressViewContainer layoutSubviews];
[UIView animateWithDuration:0.5 animations:^{
self.ProgressViewTopConstraint.constant = 0;
[self.progressViewContainer layoutSubviews];
[self.view layoutSubviews];
}];
}
self.ProgressView.progress = percent;
}
#pragma mark - download data
-(void)download1{
__weak ViewController * weekSelf = self;
weekSelf.backgroundManagedObjectContext = [[NSManagedObjectContext alloc]init];
[weekSelf.backgroundManagedObjectContext setPersistentStoreCoordinator:[[ManagedContextHelper getManagedObjectContext] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:weekSelf selector:@selector(backgroundContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:weekSelf.backgroundManagedObjectContext];
AppDelegate * appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.serverConnection callGet1:weekSelf.server managedObjectContext:weekSelf.backgroundManagedObjectContext delegate:weekSelf withCompletionHandler:^(BIResponseObject *response) {
switch (response.responseType) {
case BIResponseTypeNoInternet:
case BIResponseTypeConnectionTimeOut:
[weekSelf cancelProgresView];
break;
case BIResponseTypeOK:
[weekSelf download2];
break;
default:
[weekSelf loadModel];
[weekSelf noServerWarrning];
break;
}
}];
}
-(void)download2{
__weak ViewController * weekSelf = self;
AppDelegate * appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.serverConnection callGet2:weekSelf.server managedObjectContext:weekSelf.backgroundManagedObjectContext delegate:weekSelf withCompletionHandler:^(BIResponseObject *response) {
switch (response.responseType) {
case BIResponseTypeFactTableOK: {
weekSelf.object.downlodedDate = [NSDate date];
[weekSelf.object save:weekSelf.backgroundManagedObjectContext];
[weekSelf loadModel];
[[ManagedContextHelper getManagedObjectContext] save:nil];
}
case BIResponseTypeConnectionTimeOut:
case BIResponseTypeNoInternet:
case BIResponseTypeFactTableError:
[weekSelf cancelProgresView];
break;
default:
[weekSelf cancelProgresView];
break;
}
}];
}
#pragma mark - LOAD MODEL
-(void)loadModel{
__weak ViewController * weekSelf = self;
dispatch_async(weekSelf.coreDataQueue, ^(void){
if (!weekSelf.backgroundManagedObjectContext) {
weekSelf.backgroundManagedObjectContext = [[NSManagedObjectContext alloc]init];
[weekSelf.backgroundManagedObjectContext setPersistentStoreCoordinator:[[ManagedContextHelper getManagedObjectContext] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:weekSelf selector:@selector(backgroundContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:weekSelf.backgroundManagedObjectContext];
}
MyUIObject * uiObject = [DataBase getUIObject:weekSelf.backgroundManagedObjectContext];
weekSelf.myObject = [[UIScrollObject alloc] initWith: uiObject];
weekSelf.myObject.delegate = weekSelf;
if (uiObject && weekSelf.myObject) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
self.myObject.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.myObject];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_myObject]|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(_myObject)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(66)-[_myObject]|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(_myObject)]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.myObject attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
[self.view sendSubviewToBack:self.myObject];
[self.myObject createModel];
});
}
else {
[weekSelf dissmisView:weekSelf];
}
});
}
- (void) dissmisView: (ViewController * ) selfReference {
dispatch_async(dispatch_get_main_queue(), ^(void) {
[selfReference cancelProgresView];
if (![selfReference.presentedViewController isBeingDismissed]) {
[selfReference dismissViewControllerAnimated:YES completion:nil];
}
});
}
#pragma mark - handling multi ManagedObjectContext
- (void)backgroundContextDidSave:(NSNotification *)notification {
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(backgroundContextDidSave:)
withObject:notification
waitUntilDone:NO];
return;
}
[[ManagedContextHelper getManagedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}
...
@end
dispatch_async(self.model_queue, ^(void){
[self createPrimaryModel_newThread];
[BINotifications notifyModelIsCompletedCreating:self];
});
BINotifications
+ (void) notifyProgressUpdateWithPercent: (float) percent andNotificationString: (NSString * ) notificationString {
dispatch_async(dispatch_get_main_queue(), ^(void) {
[[NSNotificationCenter defaultCenter] postNotificationName:ProcessUpdateNotification
object:[[BINotificationsProcessUpdate alloc]
initWithPercent:percent
description:notificationString]];
});
}
-(void)callGet2: (Server *) server managedObjectContext: (NSManagedObjectContext *)managedObjectContext delegate: (id) delegate withCompletionHandler:(void (^)(BIResponseObject * response))callback
{
id<BIServerConnectionDelegate> _delegate = delegate;
[_delegate progressInProcentage2:0.0];
NSString * method = [NSString stringWithFormat:@".../%i", ...];
[self callServerWithMethod:method server:server withCallBack:^(BIResponseObject *response) {
[_delegate progressInProcentage2:0.3];
response.responseType = [self parse2:response server:server managedObjectContext:managedObjectContext delegate:_delegate];
[self setResponseTitleAndMessage:response server:server];
callback(response);
}];
}
, , .
"", ... ( .), , : D, .