使用setNeedsDisplay在后台设置CALayers动画

时间:2012-10-17 11:02:29

标签: ios

我将我的图书馆从Andriod移植到IOS,我已经取得了很大的进步,并在此过程中学到了一些关于Objective C的知识。我说一点,因为有很多东西需要学习。 Android库创建了一个surfaceView,并通过将图像直接绘制到surfaceView来完成动画。在Objective C中,我使用的是带有CALayers的UIView。

在UIView中,我动态添加加载了Sprite Sheet图像的CALayers,然后通过移动CALayer的contentsRect在CALayer中旋转Sprite图像时在UIView中移动CALayers。

这一切都在Android的后台线程中完美运行,并且不会干扰主机应用程序。在Objective C中,我尝试使用performSelectorInBackground或新的Grand Central Dispatch在后台运行它。两者似乎都在后台工作正常,将图像加载到CALayers中然后我遇到障碍:CALayers没有显示。

我知道CALayers在那里,因为当我通过点击中间的硬件按钮在模拟器中暂停应用程序然后再次单击以显示它时,CALayers看起来很棒 - 但是静态。

阅读了几天的帖子,并尝试了各种方法在UIView和个人CALayers上设置NeedsDisplay和NeedsLayout,我放弃了,我正在寻求你的帮助。

所以,请看下面的代码,让我知道我做错了什么。我在设置CALayers的框架时也遇到了问题。当我尝试使用[self setFrame:CGRectMake(0,0,spWidth,spHeight)]设置它们时 - 两个NSIntegers;我收到错误提示将CGRect发送到不兼容类型NSInteger的参数。我知道这可能是一个新手的错误。

以下是我的代码的相关部分。我会发布更多,但我希望我的错误在run方法中。

在我的自定义UIView

    if ((self = [super initWithFrame:CGRectMake(0,0,dw,dh)])){

    (initialization and defining variables)

    self.bounds = CGRectMake(0, 0, dw, dh);
    self.frame = CGRectMake(0,0,dw,dh);
    self.backgroundColor = [UIColor whiteColor];
    MainDrawLayer  = [[CALayer layer]retain];
    MainDrawLayer.bounds = CGRectMake(0, 0, dw, dh); //dw=320 dh=50.
    MainDrawLayer.frame = CGRectMake(0,0,dw,dh);

    [self.layer addSublayer:MainDrawLayer] ;
    }
    return self;

所有动作都是在我从ViewController调用的run方法中触发的。

    - (void) run {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    PGM = [[[GadsMonitor alloc] init:   @"http://www.javelin21.com/servlets/theloader" :_displaySizeW :_displaySizeH]autorelease];

   while(!PGM.adsdone){
   [NSThread sleepForTimeInterval:2.0];
    NSLog(@"The value of adsdone is %@\n", (PGM.adsdone ? @"YES" : @"NO"));
   }

   NSLog(@"Into processComponent Number in PGM.PGVarray %d ", PGM.PGVarray.count);

   GVarray = [PGM.PGVarray mutableCopy];
   NSLog(@"Into RUN after copy  GVArray %d ", GVarray.count);


   Gad * readyGad = (Gad *) [GVarray objectAtIndex:0];
   if (readyGad != nil)
   [readyGad getImages];

   NSLog(@"The value of the bool is %@\n", (readyGad.gdone ? @"YES" : @"NO"));

  while (!readyGad.gdone) {
     [NSThread sleepForTimeInterval:2.0];
     [readyGad checkImages];
    NSLog(@"The value of the readyGad.gdone is %@\n", (readyGad.gdone ? @"YES" : @"NO"));
    }
    rstop = NO;


   while (!rstop) {
    NSLog(@"The value of rstop in while is %@\n", (rstop ? @"YES" : @"NO"));

    [self rotateGames];

    stop = NO;

   while (!stop) {
        [self gameAction];
        [self paint];

   dispatch_async(dispatch_get_main_queue(), ^{
    [self setNeedsLayout]; //I have also tried self.layer
      [self  setNeedsDisplay]; //I have also tried self.layer
        });

        //These are various timers for CALayer action
        [NSThread sleepForTimeInterval:stime];
        rtime = (rtime +runGad.gslp);
        ltime += runGad.gslp;
        jtime += runGad.gslp;
        vtime += runGad.gslp;
        ftime += runGad.gslp;
        ttime += runGad.gslp;
        Stime += runGad.gslp;

        NSLog(@"After Thread Sleep rtime + gslp %f ", rtime);

        if ((runTime += runGad.gslp) >= runGad.grun) {
            stop = YES;
        }
    }

   stop = NO;
  }
  });

}

我感谢你的时间。

1 个答案:

答案 0 :(得分:0)

在iOS中,必须在主线程中执行任何UI更新代码。您不能使用GCD(除非它在mainQueue上运行)或performSelectorInBackground来更新UI。

您可以更新数据并在后台线程上执行IO,但是当您加载数据并想要显示它时,您必须切换回主线程。

尝试不这样做有时会有效,有时则无法使用,或者导致应用程序崩溃。

主线程拥有iOS中的UI更新。

此外,当您在主线程上进行工作时,您有几个选项,您可以使用performSelectorOnMainThread排队一个块

或者您可以将一个块发送到主线程GCD队列,有时您可能需要在主线程上使用dispatch_async vs dispatch_sync,如果您使用GCD,它们在每种情况下都不起作用。 performSelectorInMainthread似乎比GCD主线程队列更可靠。

因人而异