我有一个案例,当我用多线程调用方法时随机获得EXC_BAD_ACCESS (code=1, address=0x4)
异常。同样的方法,有时错误,有时不。但是我的测量表明,至少有5次运行会产生这个错误。
首先让我展示一下我的代码是如何组织的图表,这样就可以更容易地阅读代码。
我有一个View控制器处理视图并调用服务器类(存储在AppDelegate类中的实例)以获取数据。数据从服务器异步检索并存储在Core数据DB中,并在完成后调用CompleteHandler。 在这两者之间,调用服务器中的委托方法以更新ViewControllers中的进度百分比。
完成此操作后,ViewController调用构建异步构建的Model类,并从Core数据DB中读取数据。
在此步骤中,调用模型进行构建时,会发生错误。 第二个问题是,即使调用该委托方法并将正确的百分比发送到ViewController,也不会更新进度条。
这一点,以及错误随机发生的事实,让我相信它必须是线程的错误,并且很快就会释放一些对象。
我尝试使用Zombies进行调试,但没有任何显示。
代码:
的ViewController
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// THIS IS NOTIFICATIONS FROM MODEL
[[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
// METHOD THAT IS CALLED AFTER NSNOTIFICATION IS CALLED
- (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;
}
// METHODS THAT ARE CALLED WITH SERVER DELEGATES
- (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;
// build new NSManagedObjectContext
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){
// build new NSManagedObjectContext
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];
// Add model
[self.myObject createModel]; // THIS IS A LINE THAT I THINK IT BREAK,... logs are till here.
});
}
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 {
/* Make sure we're on the main thread when updating the main context */
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(backgroundContextDidSave:)
withObject:notification
waitUntilDone:NO];
return;
}
/* merge in the changes to the main context */
[[ManagedContextHelper getManagedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}
...
@end
创建模型
dispatch_async(self.model_queue, ^(void){
// Create Model in new thread
[self createPrimaryModel_newThread]; // inside here notifications are send to update progress bar.
/// Model is complete
[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];
// parse
response.responseType = [self parse2:response server:server managedObjectContext:managedObjectContext delegate:_delegate];
[self setResponseTitleAndMessage:response server:server];
callback(response);
}];
}
我知道这很多,但我真的很困惑。
代码被“清理”,因此函数名称,...被更改(我无法透露实际代码。),所以我知道名称不正确:D,但代码是真实的。