多线程问题:代码在特定点崩溃

时间:2011-02-20 19:31:56

标签: iphone multithreading

我刚刚在我的应用程序中引入了多线程,现在它在程序的某个特定点崩溃,而如果我不进行多线程,它确实有效。

FlipsideViewController.h

//
//  FlipsideViewController.h
//  iRSG
//
//  Created by Thomas van Arkel on 12-02-11.
//  Copyright 2011 Arques Software. All rights reserved.
//

#import <UIKit/UIKit.h>

@protocol FlipsideViewControllerDelegate;


@interface FlipsideViewController : UIViewController {
    id <FlipsideViewControllerDelegate> delegate;
    NSArray *timeTableArray;
    IBOutlet UIActivityIndicatorView *activityIndicator;
}

- (IBAction)getTimeTable:(UIButton *)sender;
- (IBAction)removeTimeTable:(UIButton *)sender; 

@property (nonatomic, assign) id <FlipsideViewControllerDelegate> delegate;


- (IBAction)done:(id)sender;
@end


@protocol FlipsideViewControllerDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
@end

FlipsideViewController.m

//
//  FlipsideViewController.m
//  iRSG
//
//  Created by Thomas van Arkel on 12-02-11.
//  Copyright 2011 Arques Software. All rights reserved.
//

#import "FlipsideViewController.h"
#import "TimeTableCreator.h"
#import "Lesson.h"
#import "iRSGAppDelegate.h"

@interface FlipsideViewController()
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *spinner;
@end

@implementation FlipsideViewController

@synthesize delegate;
@synthesize spinner;


- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];

}


- (IBAction)done:(id)sender {
    [self.delegate flipsideViewControllerDidFinish:self];   
}

- (IBAction)getTimeTable:(UIButton *)sender {
    activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    activityIndicator.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
    activityIndicator.center = self.view.center;
    [self.view addSubview: activityIndicator];
    [activityIndicator startAnimating];
    dispatch_queue_t downloadQueue = dispatch_queue_create("TimeTable downloader", NULL);
    timeTableArray = [[NSArray alloc] init];

    dispatch_async(downloadQueue, ^{
        NSString* settingValue = [[NSUserDefaults standardUserDefaults] stringForKey:@"partOfSchool"]; 
        if ([settingValue isEqualToString:@"upper"]) {
            NSString *studentID = [[NSUserDefaults standardUserDefaults] stringForKey:@"studentID"];
            NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://roosters.rsgslingerboslevant.nl/lichtkrant/slingerbos/leerlingen/ll_roost_%@.htm", studentID]];
            timeTableArray = [TimeTableCreator createTimeTableWithURL:url];
        } else if ([settingValue isEqualToString:@"lower"]) {
            NSString *class = [[NSUserDefaults standardUserDefaults] stringForKey:@"class"];
            if (class.length == 2) {
                NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://roosters.rsgslingerboslevant.nl/lichtkrant/Slingerbos/Klassen/K_%@.htm", class]];
                timeTableArray = [TimeTableCreator createTimeTableForLowerClassWithURL:url];
            } else if (class.length == 3) {
                NSString *beginningString = [class substringToIndex:1];
                NSString *endString = [class substringFromIndex:2];
                endString = [endString lowercaseString];
                class = [beginningString stringByAppendingString:endString];
                NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://roosters.rsgslingerboslevant.nl/lichtkrant/Slingerbos/Klassen/K_%@.htm", class]];
                timeTableArray = [TimeTableCreator createTimeTableForLowerClassWithURL:url];
            }
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            NSManagedObjectContext *managedObjectContext = nil;
            if (managedObjectContext == nil) 
            { 
                iRSGAppDelegate *appDelegate = (iRSGAppDelegate *)[[UIApplication sharedApplication] delegate];
                managedObjectContext = [appDelegate managedObjectContext];
            }

            NSFetchRequest * allLessons = [[NSFetchRequest alloc] init];
            [allLessons setEntity:[NSEntityDescription entityForName:@"Lesson" inManagedObjectContext:managedObjectContext]];
            [allLessons setIncludesPropertyValues:NO]; //only fetch the managedObjectID

            NSError * error = nil;
            NSArray * lessons = [managedObjectContext executeFetchRequest:allLessons error:&error];
            NSLog(@"Amount of lessons is %@", [NSNumber numberWithInt:[lessons count]]);
            [allLessons release];
            //error handling goes here
            for (NSManagedObject * lesson in lessons) {
                [managedObjectContext deleteObject:lesson];
            }
            iRSGAppDelegate *appDelegate = (iRSGAppDelegate *)[[UIApplication sharedApplication] delegate];
            [appDelegate saveContext];



            [appDelegate saveContext];

            for (NSArray *lessonArray in timeTableArray) {
                [Lesson lessonWithLessonArray:lessonArray inManagedObjectContext:managedObjectContext];
            } 
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"Het rooster is succesvol geïmporteerd"delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
            [alert show];
            [alert release];
            [activityIndicator stopAnimating];
        });


    });



    dispatch_release(downloadQueue);




}

- (IBAction)removeTimeTable:(UIButton *)sender {
    NSManagedObjectContext *managedObjectContext = nil;
    if (managedObjectContext == nil) { 
        iRSGAppDelegate *appDelegate = (iRSGAppDelegate *)[[UIApplication sharedApplication] delegate];
        managedObjectContext = [appDelegate managedObjectContext];
    }

    NSFetchRequest * allLessons = [[NSFetchRequest alloc] init];
    [allLessons setEntity:[NSEntityDescription entityForName:@"Lesson" inManagedObjectContext:managedObjectContext]];
    [allLessons setIncludesPropertyValues:NO]; //only fetch the managedObjectID

    NSError * error = nil;
    NSArray * lessons = [managedObjectContext executeFetchRequest:allLessons error:&error];
    NSLog(@"Amount of lessons is %@", [NSNumber numberWithInt:[lessons count]]);
    [allLessons release];
        //error handling goes here
    for (NSManagedObject * lesson in lessons) {
        [managedObjectContext deleteObject:lesson];
    }
    iRSGAppDelegate *appDelegate = (iRSGAppDelegate *)[[UIApplication sharedApplication] delegate];
    [appDelegate saveContext];
}


- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}


- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}


/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/


- (void)dealloc {

    [super dealloc];
}


@end

程序总是在这里崩溃

 for (NSArray *lessonArray in timeTableArray) {
                    [Lesson lessonWithLessonArray:lessonArray inManagedObjectContext:managedObjectContext];
                }

提前致谢

编辑源代码http://cl.ly/3k322a472A0Q0A3F0S1G

要测试它,在设置应用程序中输入'2007042'为'leerlingnummer'和'onder / bovenbouw'选择'bovenbouw'(对不起它是荷兰语,我正在为荷兰语编写代码校

我收到EXC_BAD_ACCESS错误,控制台上没有任何内容。 已解决我创建了一个新的timeTableArray属性,在设置数组时,我使用了self.timeTableArray。这就是它说它被解除分配的原因(感谢NSZombie)

4 个答案:

答案 0 :(得分:1)

原因很可能是您使用的是从不同线程创建的NSManagedObjectContext。核心数据需要在使用它的同一个线程中创建NSManagedObjectContext,即如果要从2个线程(或调度队列)访问核心数据,则必须创建2 NSManagedObjectContext's(然后可以使用)相同的NSPersistentStore)。

答案 1 :(得分:1)

你可能在回答这个问题时遇到问题,因为一般的答案是“你的代码不是线程安全的”。我知道这不是那么有用,但这是一个很大的话题(填写书籍),你很幸运能在SO上得到答案。如果您不知道线程安全意味着什么,那么您应该做一些阅读。苹果网站上有一些很好的文档,例如参见

http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/Multithreading/Introduction/Introduction.html

查看你的代码我看到很多问题,但是例如你似乎在一个线程中创建timeTableArray,同时尝试在另一个线程中使用它。这怎么办?哪个先发生?你无从知晓,每次运行它都很容易就会有所不同。如果这对你来说真的是新闻(道歉,如果不是),一个粗略的经验法则是 - 你不能从后台线程做任何核心数据,你不能从后台线程做任何GUI,你可以不要使用任何也可以从另一个线程使用的对象。

一般来说,这种多线程确实很难。

顺便说一句,如果您尝试在后台线程上下载内容,请不要这样做。您可以使用异步方法。这些已经是多线程的。

答案 2 :(得分:0)

            [Lesson lessonWithLessonArray:lessonArray inManagedObjectContext:managedObjectContext];

总是在那里崩溃,对吧?一些代码怎么样?你是如何实现lessonWithLessonArray:inManagedObjectContext:的?为什么它是一个类方法(看起来很奇怪)?

答案 3 :(得分:0)

已解决我创建了一个新的timeTableArray属性,在设置数组时,我使用了self.timeTableArray。这就是它说它被解除分配的原因(感谢NSZombie)