UIImageViewer does't update its contents until

2019-08-25 15:09发布

问题:

Okay, I have a problem with my code. I want to make some sort of grid like game using imageViewers, but when the method that changes the pictures which the imageViewers how, it only updates the screen/imageviewers once it is finished executing, not when the line that does it is actually executed. I has a method with an infinite loop in it and it changes the pictures of the imageViewers as you press buttons. The buttons call methods which change a boolean variable to true, so the main game loop knows whats been pressed by constantly checking if certain variables are true. But because the game loop never ends the screen is never updated. Is there a way to update what's on the screen during execution?

I am using this code to change the imageViewers contents:

     UIImage * white = [UIImage imageNamed: @"White.png"];
     UIImage * blue = [UIImage imageNamed: @"Blue.png"];
     int tagInt=1;
     for (int y = 0;y<10;y++){
         for (int x = 0;x<10;x++){
             UIImageView *imageView;
             imageView = [[UIImageView alloc] initWithImage:white];                 imageView.frame =CGRectMake(x*32,y*37,32,37);
             imageView.image = white;
             imageView.tag=tagInt;
             [self.view addSubview:imageView];
             tagInt++;
         }
     }
     for (int u = 1;u<20;u++){
         [NSThread sleepForTimeInterval:(1)];   
         UIImageView *g = (UIImageView*)[self.view viewWithTag:u];
         g.image =blue;
     }

This is a contrived example, because my actual code is too long, but has the same problem. It only updates on-screen after the last for loop (this delays/thread-sleep commands) finishes, not as the lines of code execute.

EDIT: Here is the project if you want any context: https://www.dropbox.com/s/cvefllnhgj0tp6g/Stacker.zip

回答1:

In iOS, all UI related stuff is done in the main (UI) thread. If you have an operation that blocks the ui thread - which means, it keeps the thread busy as you do - no view update will occur. So you will have to change your code that way, that you have a "updateView" method which changes the image views' content. This method will have to be called on a regular base, e.g. by using an NSTimer instance: https://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/nstimer_Class/Reference/NSTimer.html

Assuming, the code to update your view is named "updateView", you could define a timer like this:

NSTimer *timer;
    timer = [NSTimer scheduledTimerWithTimeInterval: 1
                        target: self 
                        selector:@selector(updateView:) 
                        userInfo: nil 
                        repeats: YES];

So the timer would call your updateView method every second and would not block the main thread which again would allow the changes you made to the view to become visible.



回答2:

I think a CA animation will do what you need. Try something like this:

#import <QuartzCore/QuartzCore.h>

- (void)imageView:(UIImageView *)imageView crossfadeTo:(UIImage *)image duration:(NSTimeInterval)duration {

    [imageView.layer removeAnimationForKey:@"animateContents"];

    CABasicAnimation *crossFade = [CABasicAnimation animationWithKeyPath:@"contents"];
    crossFade.duration = duration;
    crossFade.fromValue = (id)imageView.image.CGImage;
    crossFade.toValue = (id)image.CGImage;
    [imageView.layer addAnimation:crossFade forKey:@"animateContents"];

    imageView.image = image;
}

This can also be made into a category method on UIImageView. Call it like this:

UIImage *white = [UIImage imageNamed: @"White.png"];
UIImage *blue = [UIImage imageNamed: @"Blue.png"];

UIImageView *imageView = [[UIImageView alloc] initWithImage:white];
[self imageView:imageView crossfadeTo:blue duration:5.0];

Alternatively, this can be done with block animation calling it the same way, as follows:

- (void)imageView:(UIImageView *)imageView crossfadeTo:(UIImage *)image duration:(NSTimeInterval)duration {

    UIImageView *fadeToImageView = [[UIImageView alloc] initWithFrame:imageViewFrame];
    fadeToImageView.image = image;
    [imageView.superview insertSubview:fadeToImageView belowSubview:imageView];

    [UIView animateWithDuration:duration animations:^{
        imageView.alpha = 0.0;
    } completion:^(BOOL finished) {
        imageView.image = image;
        imageView.alpha = 1.0;
        [fadeToImageView removeFromSuperview];
    }];
}