我的线程出现问题。 在线程忙碌之后,我在2个屏幕之间发生了几次。线程不执行每一行..,断点只是在必须返回主线程时消失。 有人可以帮帮我吗?
我在卸载视图时释放线程。
谢谢,
- (void)fetchFeedDataIntoDocument
{
NSString * labelString = [NSString stringWithFormat:@"Feed Fetcher %@", self.pageTitle];
const char *label = [labelString UTF8String];
self.fetchF = dispatch_queue_create(label, NULL);
dispatch_async(self.fetchF, ^{
NSArray *feeds = [FeedFetcher getDataForJson:self.pageTitle downloadBy:@"up"];
NSDictionary *lastfeed;
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate getManagedObjectContext];
if ([feeds count] > 0)
{
lastfeed = [feeds objectAtIndex:0];
[FeedFetcher setLastUpdateIdToCatgorie:self.pageTitle WithId:[lastfeed objectForKey:@"id"] AndPulishDate:[lastfeed objectForKey:@"publish_up"]];
}
for (NSDictionary *feedInfo in feeds) {
[Feed FeedWithInfo:feedInfo InManageObject:context];
}
NSError *error = nil;
[context save:&error];
if (error){
NSLog(@"Error save : %@", error);}
dispatch_async(dispatch_get_main_queue(), ^{
[self setupFetchedResultsController];
[self.tableView reloadData];
[self downloadImagesForFeeds:feeds];
});
});
答案 0 :(得分:11)
您正在从创建它的其他线程访问managedObjectContext。这是核心数据线程规则#1。
您正在从应用代表处获取MOC。如果它是正常的Xcode生成的MOC,那么它是使用线程限制并发创建的。你甚至不能用它调用performBlock。您只能从主线程访问该MOC。期。其他任何事情都充满了火,充其量。
如果您想在单独的线程中完成所有工作,您还需要一个单独的MOC。像这样(只是键入 - 未编译)......
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
moc.parentContext = appDelegate.managedObjectContext;
[moc performBlock:^{
// Go get your remote data and whatever you want to do
// Calling save on this MOC will push the data up into the "main" MOC
// (though it is now in the main MOC it has not been saved to the store).
[moc save:&error];
}];
哪会转化为这样......
- (void)fetchFeedDataIntoDocument
{
NSString * labelString = [NSString stringWithFormat:@"Feed Fetcher %@", self.pageTitle];
const char *label = [labelString UTF8String];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *mainContext = [appDelegate getManagedObjectContext];
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
context.parentContext = mainContext;
[context performBlock:^{
NSArray *feeds = [FeedFetcher getDataForJson:self.pageTitle downloadBy:@"up"];
NSDictionary *lastfeed;
if ([feeds count] > 0)
{
lastfeed = [feeds objectAtIndex:0];
[FeedFetcher setLastUpdateIdToCatgorie:self.pageTitle WithId:[lastfeed objectForKey:@"id"] AndPulishDate:[lastfeed objectForKey:@"publish_up"]];
}
for (NSDictionary *feedInfo in feeds) {
[Feed FeedWithInfo:feedInfo InManageObject:context];
}
NSError *error = nil;
[context save:&error];
if (error){
NSLog(@"Error save : %@", error);}
DO you really want to continue on error?
dispatch_async(dispatch_get_main_queue(), ^{
// Data has been pushed into main context from the background
// but it still needs to be saved to store...
// Do not forget to perform error handling...
NSError *error = nil;
[mainContext save:&error];
[self setupFetchedResultsController];
[self.tableView reloadData];
[self downloadImagesForFeeds:feeds];
});
});
修改强>
Xcode生成的用于创建MOC的代码使用init,它使用NSConfinementConcurrencyType。您可以使用MainConcurrency替换它,没有任何问题,但可以获得多种好处。
在您的app委托文件中,替换...
__managedObjectContext = [[NSManagedObjectContext alloc] init];
有了......
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
现在,您的主要MOC可以是“父级”,您也可以在其上调用performBlock。
答案 1 :(得分:0)
更改以下代码..
dispatch_queue_t queue1 = dispatch_queue_create("com.MyApp.AppTask",NULL);
dispatch_queue_t main = dispatch_get_main_queue();
dispatch_async(queue1,
^{
dispatch_async(main,
^{
[self setupFetchedResultsController];
[self.tableView reloadData];
[self downloadImagesForFeeds:feeds];
});
});
希望,这会对你有所帮助
答案 2 :(得分:0)
这样做...
-(void)functionToCallFetch {
[self performSelectorInBackground:@selector(fetchFeedDataIntoDocument) withObject:nil];
}
- (void)fetchFeedDataIntoDocument
{
NSArray *feeds = [FeedFetcher getDataForJson:self.pageTitle downloadBy:@"up"];
NSDictionary *lastfeed;
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate getManagedObjectContext];
if ([feeds count] > 0)
{
lastfeed = [feeds objectAtIndex:0];
[FeedFetcher setLastUpdateIdToCatgorie:self.pageTitle WithId:[lastfeed objectForKey:@"id"] AndPulishDate:[lastfeed objectForKey:@"publish_up"]];
}
for (NSDictionary *feedInfo in feeds) {
[Feed FeedWithInfo:feedInfo InManageObject:context];
}
NSError *error = nil;
[context save:&error];
if (error){
NSLog(@"Error save : %@", error);}
//dispatch_async(dispatch_get_main_queue(), ^{
// [self setupFetchedResultsController];
// [self.tableView reloadData];
// [self downloadImagesForFeeds:feeds];
//});
[self performSelectorOnMainThread:@selector(setupFetchedResultsController) withObject:nil waitUntilDone:NO];
[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
[self performSelectorOnMainThread:@selector(downloadImagesForFeeds:) withObject:feeds waitUntilDone:NO];
}
也许这会更好用吗?
答案 3 :(得分:0)
您是否尝试构建如下方法:
- (void)methodToBePerformedOnMainThread{
[self setupFetchedResultsController];
[self.tableView reloadData];
[self downloadImagesForFeeds:feeds];
}
并用
调用它[self performSelectorOnMainThread:@selector(methodToBePerformedOnMainThread) withObject:nil waitUntilDone:NO];
在fetchFeedDataIntoDocument
编辑:
您是否尝试用NSOperationQueue代替dispatch_queue来包装它?
喜欢:
NSOperationQueue *operationQueue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(fetchFeedDataIntoDocument) object:nil];
if(operation != nil){
[operationQueue addOperation:operation];