我刚刚在我的应用程序中引入了多线程,现在它在程序的某个特定点崩溃,而如果我不进行多线程,它确实有效。
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)
答案 0 :(得分:1)
原因很可能是您使用的是从不同线程创建的NSManagedObjectContext
。核心数据需要在使用它的同一个线程中创建NSManagedObjectContext
,即如果要从2个线程(或调度队列)访问核心数据,则必须创建2 NSManagedObjectContext's
(然后可以使用)相同的NSPersistentStore
)。
答案 1 :(得分:1)
你可能在回答这个问题时遇到问题,因为一般的答案是“你的代码不是线程安全的”。我知道这不是那么有用,但这是一个很大的话题(填写书籍),你很幸运能在SO上得到答案。如果您不知道线程安全意味着什么,那么您应该做一些阅读。苹果网站上有一些很好的文档,例如参见
查看你的代码我看到很多问题,但是例如你似乎在一个线程中创建timeTableArray,同时尝试在另一个线程中使用它。这怎么办?哪个先发生?你无从知晓,每次运行它都很容易就会有所不同。如果这对你来说真的是新闻(道歉,如果不是),一个粗略的经验法则是 - 你不能从后台线程做任何核心数据,你不能从后台线程做任何GUI,你可以不要使用任何也可以从另一个线程使用的对象。
一般来说,这种多线程确实很难。
顺便说一句,如果您尝试在后台线程上下载内容,请不要这样做。您可以使用异步方法。这些已经是多线程的。
答案 2 :(得分:0)
[Lesson lessonWithLessonArray:lessonArray inManagedObjectContext:managedObjectContext];
总是在那里崩溃,对吧?一些代码怎么样?你是如何实现lessonWithLessonArray:inManagedObjectContext:
的?为什么它是一个类方法(看起来很奇怪)?
答案 3 :(得分:0)
已解决我创建了一个新的timeTableArray属性,在设置数组时,我使用了self.timeTableArray。这就是它说它被解除分配的原因(感谢NSZombie)