在iOS

时间:2016-09-21 17:10:16

标签: ios objective-c multithreading exc-bad-access

我有一个案例,当我用多线程调用方法时随机获得EXC_BAD_ACCESS (code=1, address=0x4)异常。同样的方法,有时错误,有时不。但是我的测量表明,至少有5次运行会产生这个错误。

首先让我展示一下我的代码是如何组织的图表,这样就可以更容易地阅读代码。

enter image description here

我有一个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,但代码是真实的。

0 个答案:

没有答案