代码之家  ›  专栏  ›  技术社区  ›  Shingoo

从不是主线程的线程更改gui?

  •  1
  • Shingoo  · 技术社区  · 14 年前

    我的想法是有一个视图,当一些东西是在幕后计算时,它会向用户显示。这是一个高度为30px的视图,包含一个uiActivityIndicatorView和一个uiLabel,显示当前正在计算的内容。

    我试图通过使用以下方法使用activityhandler来实现它:

    - (void)newActivityStarted{
        [self performSelectorOnMainThread:@selector(showActivityViewer) withObject:nil waitUntilDone:NO];
    }
    
    - (void)activityStopped{
        [self performSelectorOnMainThread:@selector(hideActivityViewer) withObject:nil waitUntilDone:NO];
    }
    
    - (void)changeInfoText:(NSString*)infoText{
        [activityView.infoLabel performSelectorOnMainThread:@selector(setText:) withObject:infoText waitUntilDone:NO];
    }
    

    以下是在主线程上调用的方法:

    -(void)hideActivityViewer{
        CGContextRef context = UIGraphicsGetCurrentContext();
        [UIView beginAnimations:nil context:context];
    
        [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
        [UIView setAnimationDuration:0.2];
        [UIView setAnimationDelegate: self];
        [UIView setAnimationDidStopSelector:@selector(closeActivityViewer:finished:context:)];
        [activityView setFrame:CGRectMake(320, 10, 320, 30)];
    
        [UIView commitAnimations];
    }
    
    -(void)closeActivityViewer:(NSString*)id finished:(BOOL)finished context:(id)context{
    
        [activityView removeFromSuperview];
        [activityView release];
        activityView = nil;
    }
    
    -(void)showActivityViewer{
    
        activityView = [[BCActivityView alloc] initWithFrame:CGRectMake(320, 10, 320, 30)];
        [activityView.infoLabel setText:NSLocalizedString(@"WorkInProgressKey",nil)];
    
        [[(MyAppDelegate*)[[UIApplication sharedApplication] delegate] window] addSubview: activityView];
    
        CGContextRef context = UIGraphicsGetCurrentContext();
        [UIView beginAnimations:nil context:context];
    
        [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
        [UIView setAnimationDuration:0.2];
        [activityView setFrame:CGRectMake(0, 10, 320, 30)];
    
        [UIView commitAnimations];
    }
    

    newActivityStarted、activityStopped和changeInfoText方法由正在计算一些耗时数据的后台线程调用。

    将按如下方式打开耗时的线程:

    NSInvocationOperation* operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(calculateData) object:nil];
    [[[NSOperationQueue new] autorelease] addOperation:operation];
    [operation release];
    

    计算过程如下:

    -(void) calculateData{
        [[ActivityIndicatorHandler instance] newActivityStarted];
        [[ActivityIndicatorHandler instance] changeInfoText:NSLocalizedString(@"InitializingForecastKey", nil)];
    
        //Do something time consuming
    
        [[ActivityIndicatorHandler instance] activityStopped];
    }
    

    其效果是,在完成整个计算之后,显示并隐藏活动视图。我希望gui显示视图并负责用户交互,而计算是在后台完成的。但是,即使我在计算中有一个断点,在计算线程完成其工作以及活动视图未显示之前,该视图将不可用…我不知道怎么了…

    有人知道吗?

    3 回复  |  直到 14 年前
        1
  •  2
  •   Chip Coons    14 年前
    @implementation ActivityHandler;
    
    //....
    - (void)newActivityStarted{
        [self performSelectorOnMainThread:@selector(showActivityViewer) withObject:nil waitUntilDone:NO];
    }
    
    - (void)activityStopped{
        [self performSelectorOnMainThread:@selector(hideActivityViewer) withObject:nil waitUntilDone:NO];
    }
    
    - (void)changeInfoText:(NSString*)infoText{
        [activityView.infoLabel performSelectorOnMainThread:@selector(setText:) withObject:infoText waitUntilDone:NO];
    }
    
    
    - (NSInvocationOperation*)myOperation:
    {
        NSInvocationOperation* operation = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(calculateData) object:nil] autorelease];
        return operation;
    }
    

    在其他一些方法中,可能是应用程序委托,在初始值设定项中设置本地队列:

    NSOperaionQueue* aQueue = [[[NSOperationQueue alloc] init] retain];  //release in dealloc
    ActivityHandler* myHandler [[[ActivityHandler alloc] init] retain];  //release in dealloc
    
    Have a method to add ops to the queue:
    
    -(void)queueOperation:(NSInvocationOperation*)anOp;
    {
        [aQueue addOperation:anOp];
    }
    
    -(IBAction*)startCalcs:(id)sender;
    {
        [self queueOperation:[myHandler myOperation]];
    
    }
    
        2
  •  0
  •   Felix Lamouroux    14 年前

    您是否尝试通过执行以下操作来调用计算:

    [self performSelectorInBackground:@selector(calculateData) withObject:nil];
    
        3
  •  0
  •   HiveHicks    14 年前

    我想您需要考虑performselectornmainthread:withobject:waituntildone:method