Note that there are some explanatory texts on larger screens.

plurals
  1. POCATransaction begin/commit in loop not being honored, all happens at once
    text
    copied!<p>I'm working through the 4th ed. of the Hillegass/Preble Cocoa book and have hit a snag I can't understand in Core Animation.</p> <p>In particular, I have the following loop that presents a list of images, supposedly one-at-a-time, into a layer-hosting view. The expected result is that I should see each image fly out one-at-a-time as <code>presentImage</code> is called. The actual result is that the view stays empty until the loop is complete and then the images fly out all-at-once. During the delay, I see the multiple log messages indicating the multiple calls to <code>presentImage</code>. When those log messages stop, indicating the loop is done, then all the images fly out at once.</p> <pre><code>// loop to present each image in list of URLs // called at end of applicationDidFinishLaunching NSTimeInterval t0 = [NSDate timeIntervalSinceReferenceDate]; for(id url in urls) { NSImage *img = [[NSImage alloc] initWithContentsOfURL:url]; if(!img) continue; NSImage *thumbImg = [self thumbImageFromImage:img]; [self presentImage:thumbImg]; NSString *dt = [NSString stringWithFormat:@"%0.1fs", [NSDate timeIntervalSinceReferenceDate]-t0]; NSLog(@"Presented %@ at %@ sec",url,dt); } </code></pre> <p>The <code>thumbImageFromImage</code> method does just what you'd think (creates a smaller image). The code for <code>presentImage</code> is as follows:</p> <pre><code>- (void)presentImage:(NSImage *)image { CGRect superlayerBounds = view.layer.bounds; NSPoint center = NSMakePoint(CGRectGetMidX(superlayerBounds), CGRectGetMidY(superlayerBounds)); NSRect imageBounds = NSMakeRect(0, 0, image.size.width, image.size.height); CGPoint randomPoint = CGPointMake(CGRectGetMaxX(superlayerBounds)*(double)random()/(double)RAND_MAX, CGRectGetMaxY(superlayerBounds)*(double)random()/(double)RAND_MAX); CAMediaTimingFunction *tf = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; CABasicAnimation *posAnim = [CABasicAnimation animation]; posAnim.fromValue = [NSValue valueWithPoint:center]; posAnim.duration = 1.5; posAnim.timingFunction = tf; CABasicAnimation *bdsAnim = [CABasicAnimation animation]; bdsAnim.fromValue = [NSValue valueWithRect:NSZeroRect]; bdsAnim.duration = 1.5; bdsAnim.timingFunction = tf; CALayer *layer = [CALayer layer]; layer.contents = image; layer.actions = [NSDictionary dictionaryWithObjectsAndKeys:posAnim,@"position", bdsAnim, @"bounds", nil]; [CATransaction begin]; [view.layer addSublayer:layer]; layer.position = randomPoint; layer.bounds = NSRectToCGRect(imageBounds); [CATransaction commit]; } </code></pre> <p>The observed result is as if the <code>[CATransaction begin]</code> and <code>[CATransaction commit]</code> calls are bracketing the <code>for</code> loop rather than the call to <code>addSublayer</code> inside <code>presentImage</code>. In fact, I do observe the same all-at-once behavior if I remove the <code>[CATransaction begin]</code> and <code>[CATransaction commit]</code> from inside <code>presentImage</code> and instead bracket the <code>for</code> loop. Actually, I observe the same all-at-once behavior if I remove calls to <code>[CATransaction begin]</code> and <code>[CATransaction commit]</code> altogether.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload