1

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

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

这一切都在 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;
  }
  });

}

我感谢你的时间。

4

1 回答 1

0

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

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

尝试不这样做有时会奏效,有时不会,或者使您的应用程序崩溃。

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

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

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

ymmv

于 2012-10-17T11:05:52.377 回答