I need to change the pictures in a loop in the UIImageView . If something about the standard methods of animation, which UIImageView owns UIImageView I vkurse, but it is necessary to make a loop. Here is my code:

 - (void)startAnimating { for (int i = 0; i < allImages.count; i++) { sleep(1); [self changeImageByIndex:i]; } } - (void)changeImageByIndex:(NSInteger)index { [imageView setImage:[allImages objectAtIndex:index]]; } 

in the array allImages are all the pictures. do not pay attention to sleep(1) either - this is a temporary crutch that will be removed) the fact that the body of the cycle is actually executed once every 1 second, BUT! The image is shown only the latest. Those. during the cycle, nothing is noticeable, but at the end of the OCP! and we see the last picture. Why are they not updated?

  • Cool. Apparently, the UI updates do not occur during the execution of for, and when all iterations have passed and the program has left for, the entire queue is immediately processed. - Max Mikheyenko
  • one
    You runloop with sleep, that's what's not updated - Cy-4AH
  • That's specifically for , Max wrote everything correctly. In real projects you shouldn't do that. For such a task, either start the animation in UIImageView , or by timers and, if you want to do it right, then CADisplayLink (something like the timers on update on the screen) - Gralex
  • @ Cy-4AH is not the problem. make for 10k reps without sleep and change the picture in it - the result will be the same, it will change after the application exits the loop (10k repetitions so that it is long enough to see) - Max Mikheyenko
  • @MaxMikheyenko, well, click here. He himself wrote in his answer: the for loop runs on the main thread, actually blocking it. And now you say the problem is not that. Yes, without a slip, it will not change 10k times and one, the last, when the cycle in the runloop runs. - Cy-4AH

4 answers 4

As it turned out, the for loop runs on the main thread, effectively blocking it, so the UI updates cannot be executed until the loop ends. To overcome this, I suggest that the cycle be run on a non-main thread, but send UI updates to the main one.

 - (void)startAnimating { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ for (int i = 0; i < allImages.count; i++) { sleep(1); [self changeImageByIndex:i]; } }); } - (void)changeImageByIndex:(NSInteger)index { dispatch_async(dispatch_get_main_queue(), ^{ [imageView setImage:[allImages objectAtIndex:index]]; }); } 

    https://stackoverflow.com/questions/22994402/function-after-animation-image-sequence Here is the most correct solution, CADisplayLink , the time from the last picture change is summed up as soon as it is longer than one frame - the next picture is set. By setting the last frame display link is killed. In your case, you completely occupy the main thread, because sleep does not give control to the UI subsystem, so imageView redrawing is not called until the UI subsystem system gains control over the main thread. Timers and dispatches are half measures, and to apply online changes to the UI, CADisplayLink appropriate to use.

       - (void)startAnimatingWhithDuration:(NSInteger)duration { [self.allImages enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { [UIView transitionWithView:self.imageView duration:duration options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ } completion:^(BOOL finished) { [self.imageView setImage:obj]; }]; }]; } 
      • Please try to write more detailed answers. I am sure the author of the question would be grateful for your expert commentary on the code above. - Nicolas Chabanovsky

      Hello

       func startAnimation() { timer = NSTimer.scheduledTimerWithTimeInterval( 1, target: self, selector: #selector(nextImage), userInfo: nil, repeats: true) } func nextImage() { imageIndex += 1 print("TICK = \(imageIndex)") if imageIndex == 5 { timer?.invalidate() } } 

      That's all you need to know. You can do anything with this timer.

      • Please note that the author writes that he is aware of how animations work, but for his task, he asks for suggestions on how to do this using a loop. Again in question is the objective-c tag - Max Mikheyenko
      • I noticed very well that in this context all that is needed from the cycle is an index. And the code here is not so difficult to rewrite on the objective, I would write with words, just more clearly - andryuwka
      • so what is not immediately on the php code? it would be easy too - Max Mikheyenko
      • I thank everyone for the answer. I'll get to the code in an hour and try. And the fact that it’s written on SWIFT is ok, I’ll understand) - Andrey Evstratenko