CALayer position contains NaN: [nan nan] During Drag and Drop

Can't seem to track this one down. My app creates a dragging session. During drag and drop, if I drag around the screen for awhile I sometimes hit this crash.


CALayer position contains NaN: [nan nan]

2016-01-14 18:08:00.753 MY APP NAME [23373:356523] (

0 CoreFoundation 0x00007fff9b5e8ae2 __exceptionPreprocess + 178

1 libobjc.A.dylib 0x00007fff9791e73c objc_exception_throw + 48

2 CoreFoundation 0x00007fff9b5e898d +[NSException raise:format:] + 205

3 QuartzCore 0x00007fff99f5914e _ZN2CA5Layer12set_positionERKNS_4Vec2IdEEb + 152

4 QuartzCore 0x00007fff99f590ae -[CALayer setPosition:] + 44

5 HIToolbox 0x00007fff8cc5e711 _ZL20UpdateLayerPositionsP14OpaqueCoreDrag + 630

6 HIToolbox 0x00007fff8ce830f8 _Z29UnflockAnimationTimerCallbackP16__CFRunLoopTimerPv + 759

7 CoreFoundation 0x00007fff9b52ebc4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20

8 CoreFoundation 0x00007fff9b52e853 __CFRunLoopDoTimer + 1075

9 CoreFoundation 0x00007fff9b5ace6a __CFRunLoopDoTimers + 298

10 CoreFoundation 0x00007fff9b4e9cd1 __CFRunLoopRun + 1841

11 CoreFoundation 0x00007fff9b4e9338 CFRunLoopRunSpecific + 296

12 CoreFoundation 0x00007fff9b570db5 CFMessagePortSendRequest + 949

13 HIServices 0x00007fff867017a8 SendDragIPCMessage + 530

14 HIServices 0x00007fff866febdd CoreDragMessageHandler + 1321

15 CoreFoundation 0x00007fff9b571238 __CFMessagePortPerform + 584

16 CoreFoundation 0x00007fff9b4f8839 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41

17 CoreFoundation 0x00007fff9b4f87a9 __CFRunLoopDoSource1 + 473

18 CoreFoundation 0x00007fff9b4e9e1b __CFRunLoopRun + 2171

19 CoreFoundation 0x00007fff9b4e9338 CFRunLoopRunSpecific + 296

20 HIToolbox 0x00007fff8cc1f935 RunCurrentEventLoopInMode + 235

21 HIToolbox 0x00007fff8cc1f76f ReceiveNextEventCommon + 432

22 HIToolbox 0x00007fff8cc1f5af _BlockUntilNextEventMatchingListInModeWithFilter + 71

23 AppKit 0x00007fff8bf930ee _DPSNextEvent + 1067

24 AppKit 0x00007fff8c35f943 -[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 454

25 AppKit 0x00007fff8c1a4f9c NSCoreDragCGEventBlockingProc + 135

26 HIServices 0x00007fff866f867e SampleMouseAndKeyboard + 141

27 HIServices 0x00007fff866f8374 DragInApplication + 50

28 HIServices 0x00007fff866f7403 CoreDragStartDragging + 705

29 AppKit 0x00007fff8c1a2171 -[NSCoreDragManager _dragUntilMouseUp:accepted:] + 1010

30 AppKit 0x00007fff8c47fbbe _handleBeginDraggingSession + 97

31 CoreFoundation 0x00007fff9b4f7e37 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23

32 CoreFoundation 0x00007fff9b4f7da7 __CFRunLoopDoObservers + 391

33 CoreFoundation 0x00007fff9b4e9a3a __CFRunLoopRun + 1178

34 CoreFoundation 0x00007fff9b4e9338 CFRunLoopRunSpecific + 296

35 HIToolbox 0x00007fff8cc1f935 RunCurrentEventLoopInMode + 235

36 HIToolbox 0x00007fff8cc1f76f ReceiveNextEventCommon + 432

37 HIToolbox 0x00007fff8cc1f5af _BlockUntilNextEventMatchingListInModeWithFilter + 71

38 AppKit 0x00007fff8bf930ee _DPSNextEvent + 1067

39 AppKit 0x00007fff8c35f943 -[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 454

40 AppKit 0x00007fff8bf88fc8 -[NSApplication run] + 682

41 AppKit 0x00007fff8bf0b520 NSApplicationMain + 1176

42 MY APP NAME 0x0000000100093602 main + 34

43 libdyld.dylib 0x00007fff99f425ad start + 1


Any ideas as to what can cause it? I don't see anything helpful in the debugger. Adding an exception breakpoint doesn't show me anything helpful either.

I've seen this pop up a few times. I don't remember what I did to fix it, but I think it had something to do with a bad constraint setup.

Thanks for responding. Don't think that's the case for me. I'm not using autolayout 😮

Hmm. You aren't doing anything funny with your layer backing, are you?

I don't think so. I have a customized IKImageBrowserView subclass, with some custom cells. I draw a few extra things in a cell subclass layer, but I don't do much Core Animation myself in this app.


This seems to happen when I drag the images back and forth from my window to Finder over and over again..it doesn't happen consistently though, hard to reproduce.

Right, but when I experienced this issue, I never had to change any Core Animation code in order to fix it. It had at least something to do with view layout and the layer backing. It might have been a width or height accidentally getting set to 0, but I really don't remember for sure. It wasn't a hard fix, otherwise I'd remember what I had to do! 🙂

I was logging out the frame of the dragging item I set... I didn't hit any 0 frame sizes, but i'll try to look out for that a bit more.


I figured that must have been it too, and somewhere under the covers OS X was using the frame size as a reference and dividing by 0...but I didn't find it yet.

Well, I'll keep trying to remember what I did to fix the issue…


Do let me know if you find anything else that's interesting—I'd love to hear it!

I think I got it. When many items are being dragged at once, I capped the number of visible items to a max amount. Since in the UI, the icons get stacked on top of eachother with a badge showing the amount dragged, I decided to set the imageComponentsProvider to nil on dragging items after the max is exceeded. It seems pointless to create a bunch of images that can't be seen.


The block may be set to nil, meaning that this drag item has no image.


Pretty sure hiding the dragging items this way can cause the issue....I had this before to hide the dragging item...prior to the last update:


[dragItem setDraggingFrame:NSZeroRect contents:nil];


And didn't hit the issue before...but I got an annoying nonnull warning for the contents param...so I changed it...


I capped the number of drag images to 15...and decided to stack them...it seems pretty wasteful to make an image for every item especially when you stack them...I don't know if I should revert the code or pass in blank image as the contents...or just make an image for every since dragging item.

Good work isolating the issue!


Here's an idea: try adding a bit of context-sensitive information into the contents provider to implement the cap, like this:

var timesCalled = 0
var itemCap = 15

dragItem.imageComponentsProvider = {
     timesCalled += 1
     if timesCalled > itemCap {
          //Return an empty image array
          return []
     } else {
          //Process and return the drag images
     }
}


This way, you won't be fooling around with nil and NSZeroRect. Give it a try and let me know how it works! 🙂

Here's what I was doing in update dragging items section in one view...


  __block NSUInteger numberOfDragItems = 0;
   const NSUInteger maxNumberOfDragItems = 15;
    
        [sender enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationClearNonenumeratedImages
                                          forView:self
                                          classes:@[[NSURL class]]
                                    searchOptions:@{NSPasteboardURLReadingFileURLsOnlyKey: @(YES)}
                                       usingBlock:^(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop)
         {
             if (numberOfDragItems < maxNumberOfDragItems)
             {
                 NSURL *urlForItem = draggingItem.item;
             
                 NSImage *dragImage = doGetDragImageForURL(urlForItem);
             
                 [draggingItem setDraggingFrame:NSMakeRect(0.0,
                                                           0.0,
                                                           dragImage.size.width,
                                                           dragImage.size.height)
                                       contents:dragImage];
             }
             else { NSLog(@"whoops"); }
         
             numberOfDragItems++;

              if (numberOfDragItems >= maxNumberOfDragItems) {  *stop = YES; }
         }];


For the items beyond max...they don't hide though, they stay in there current formation....which isn't what I'm after. I want them to all stack up.


I changed it the code to this based on your previous post:


[sender enumerateDraggingItemsWithOptions:0
                                          forView:self
                                          classes:@[[NSURL class]]
                                    searchOptions:@{NSPasteboardURLReadingFileURLsOnlyKey: @(YES)}
                                       usingBlock:^(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop)
         {
             if (numberOfDragItems < maxNumberOfDragItems)
             {
                 NSURL *urlForItem = draggingItem.item;
              
                 NSImage *dragImage = doGetDragImageForURL(urlForItem);
              
                 [draggingItem setDraggingFrame:NSMakeRect(0.0,
                                                           0.0,
                                                           dragImage.size.width,
                                                           dragImage.size.height)
                                       contents:dragImage];
             }
             else
             {
                 draggingItem.imageComponentsProvider = ^NSArray<NSDraggingImageComponent *> * _Nonnull
                 {
                     return @[];
                 };
             }
          
             numberOfDragItems++;
         }];



So far, I haven't hit the issue yet... will have to do more testing. Not sure if i'm better off keeping track of the # of times its called in the imageComponentsBlock itself like in your sample.


Shouldn't setting the imageComponentsProvider to nil, or returning an empty array, or setting the contents to nil, all behave the same way?

By, "I haven't hit the issue yet," do you mean that it's not crashing anymore?

Actually I'm still hitting the bug when returning an empty array from the image components provider block..

In my limited testing...I wasn't hitting the crash, but I just hit it. Since it's difficult to reproduce...I still wasn't confident that that fixed it...I did just hit the crash again though...

Here's the only other thing I can think of trying right now. None of this really feels elegant...


On the items I want to 'hide'...


[draggingItem setDraggingFrame:NSMakeRect(0.0, 0.0, 1.0, 1.0) contents:EmtpyDragImage];


EmptyDragImage is just an instance of NSImage...with a size of 1.0, 1.0.

no crashes with a dummy image in there, but sometimes no images show up at all...so I guess the way the system stacks the images is unpredicatable...

Guess I will just return a imageComponentsProvider for all of them and trust that OS X will do a decent job making sure not to make too many images. I wasn't using the block before, I was just setting the images directly...so I'm hoping if I create the image in the block I'll get better performance.

What I can't figure out, is how to position a NSDraggingImageComponent. The coordinate system seems whacky? I tried using the image size and the draggingFrame to calculate the frame for the component, but the images go everywhere. Say I want to position all the drag images center on the mouse location (stacked)...do you know how to calculate it?

  NSRect draggingRect = draggingItem.draggingFrame;

//in the block...

CGFloat x = (draggingRect.size.width/2.0)-(sizeForItem/2.0);
CGFloat y = (draggingRect.size.height/2.0)-(sizeForItem/2.0);

imageComponent.frame = NSMakeRect(x, y , sizeForItem, sizeForItem);
CALayer position contains NaN: [nan nan] During Drag and Drop
 
 
Q