简体   繁体   English

iOS - Thread不会回到主线程

[英]iOS - Thread does not going back to the main thread

I having trouble with my threads. 我的线程有问题。 After i segue a couple of times between 2 screen when the thread is busy. 在线程忙碌之后,我在2个屏幕之间发生了几次。 The thread don't perform every line.., The breakpoint just disappear when it has to return to the main thread. 线程不执行每一行..,断点只是在必须返回主线程时消失。 Can somebody please help me ? 有人能帮帮我吗 ?

I release the thread when the view is unload. 我在卸载视图时释放线程。

Thanks, 谢谢,

- (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];
        });

    });

You are accessing the managedObjectContext from a different thread from where it was created. 您从与创建它的位置不同的线程访问managedObjectContext。 This is Core Data Threading Rule #1. 这是核心数据线程规则#1。

You are getting the MOC from the app delegate. 您正在从应用代表处获取MOC。 If it's the normal Xcode-generated MOC, then it is created with thread-confinement concurrency. 如果它是正常的Xcode生成的MOC,那么它是使用线程限制并发创建的。 You can't even call performBlock with it. 你甚至不能用它调用performBlock。 You can only access that MOC from the main thread. 您只能从主线程访问该MOC。 Period. 期。 Anything else is playing with fire, at best. 充其量只是玩火,充其量。

If you want to do all the work in a separate thread, you need a separate MOC as well. 如果要在单独的线程中完成所有工作,还需要单独的MOC。 Like this (just typed - not compiled)... 像这样(只是键入 - 未编译)...

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];
}];

Which would translate into something like this... 哪个会翻译成这样的......

- (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];
        });

    });

EDIT 编辑

The code generated by Xcode for creating the MOC uses init, which uses NSConfinementConcurrencyType. Xcode生成的用于创建MOC的代码使用init,它使用NSConfinementConcurrencyType。 You can replace it with MainConcurrency, without any problems, but get several benefits. 您可以使用MainConcurrency替换它,没有任何问题,但可以获得多种好处。

In your app delegate file, replace... 在您的app委托文件中,替换...

    __managedObjectContext = [[NSManagedObjectContext alloc] init];

with this... 有了这个...

    __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

Now, your main MOC can be "parented" and you can also call performBlock on it as well. 现在,您的主要MOC可以是“父级”,您也可以在其上调用performBlock。

Change following code.. 更改以下代码..

   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];

                                  });

               });  

Hope, this will help you 希望这个能对您有所帮助

what about doing this... 这样做...

-(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];


}

Maybe that would work better? 也许这会更好?

Did you try building a method like : 您是否尝试构建如下方法:

- (void)methodToBePerformedOnMainThread{
        [self setupFetchedResultsController];
        [self.tableView reloadData];
        [self downloadImagesForFeeds:feeds];
}

and call it with 并称之为

[self performSelectorOnMainThread:@selector(methodToBePerformedOnMainThread) withObject:nil waitUntilDone:NO];

at the end of fetchFeedDataIntoDocument fetchFeedDataIntoDocument

Edit : 编辑:

Did you try to wrap it with NSOperationQueue in place of dispatch_queue ? 您是否尝试用NSOperationQueue代替dispatch_queue来包装它?

Like : 喜欢 :

NSOperationQueue *operationQueue = [NSOperationQueue new];

NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(fetchFeedDataIntoDocument) object:nil];

if(operation != nil){
    [operationQueue addOperation:operation];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 iOS - 应用程序:didFinishLaunchingWithOptions在主线程中执行吗? - iOS - Does application:didFinishLaunchingWithOptions execute in main thread? NSURLConnection阻止主线程吗? - Does NSURLConnection block the main thread? 使用主线程而不是辅助线程回叫委托? - Call back to delegate using the main thread rather than secondary thread? 使用NSInvocationOperation将消息发送回主线程? - Using NSInvocationOperation to send messages back to the main thread? 使用通知与IOS应用程序的主线程通信可以吗? (请参见performSelectorOnMainThread) - is it ok to use of a notification to communication back to the main thread of an IOS app? (cf performSelectorOnMainThread) iOS:在主线程以外的线程中调用 UIApplication 的方法是否安全? - iOS: is calling methods of UIApplication in thread other than the main thread safe? 在iOS上将消息从后台线程发送到主线程 - Sending messages from background thread to main thread on iOS 什么时候不在iOS应用程序的主线程上执行任何操作? - When are things not executed on the main thread in an iOS app? 如何从iOS主线程上的UIProgressBar更新 - How to update from UIProgressBar on main thread in iOS 主线程阻塞导致应用程序在iOS 8中崩溃 - main thread blockage is causing app to crash in iOS 8
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM