This may be a minor issue... but it looks like a race condition. I can reliably reproduce the following NSRangeException.
2014-07-01 08:20:02.324 XXXXXX 2[7302:60b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
0x1e1698: blt 0x1e170a ; -[IGFlowLayoutView insertItemAtIndex:] + 398 at IGFlowLayoutView.m:877
0x1e169a: mov r0, r8
0x1e169c: mov r1, r6
0x1e169e: blx 0x21ad2c ; symbol stub for: objc_msgSend
0x1e16a2: ldr r1, [sp, #0x18]
0x1e16a4: adds r2, r0, #0x1
0x1e16a6: mov r0, r8
0x1e16a8: blx 0x21ad2c ; symbol stub for: objc_msgSend
0x1e16ac: ldr r1, [sp, #0x1c]
0x1e16ae: mov r0, r5
0x1e16b0: mov r4, r0
0x1e16b2: ldr r5, [r0, r1]
0x1e16b4: mov r0, r8
0x1e16b6: mov r1, r6
0x1e16b8: blx 0x21ad2c ; symbol stub for: objc_msgSend
0x1e16bc: ldr r1, [sp, #0x20]
0x1e16be: mov r2, r0
0x1e16c0: mov r0, r5
0x1e16c2: blx 0x21ad2c ; symbol stub for: objc_msgSend
0x1e16c6: mov r7, r7
0x1e16c8: blx 0x21ad4c ; symbol stub for: objc_retainAutoreleasedReturnValue
0x1e16cc: mov r11, r0
0x1e16ce: add r0, sp, #0x4c
0x1e16d0: cmp.w r11, #0x0
0x1e16d4: bne 0x1e16e4 ; -[IGFlowLayoutView insertItemAtIndex:] + 360 at IGFlowLayoutView.m:875
0x1e16d6: vst1.32 {d8, d9}, [r0]
0x1e16da: movs r0, #0x0
0x1e16dc: movs r1, #0x0
0x1e16de: movs r3, #0x0
0x1e16e0: movs r2, #0x0
0x1e16e2: b 0x1e16f4 ; -[IGFlowLayoutView insertItemAtIndex:] + 376 at IGFlowLayoutView.m:875
0x1e16e4: ldr r2, [sp, #0x10]
0x1e16e6: mov r1, r11
0x1e16e8: blx 0x21ad38 ; symbol stub for: objc_msgSend_stret
0x1e16ec: ldr r2, [sp, #0x4c]
0x1e16ee: ldr r3, [sp, #0x50]
0x1e16f0: ldr r1, [sp, #0x54]
0x1e16f2: ldr r0, [sp, #0x58]
-(void)viewWillAppear:(BOOL)animated
{
[self.flowView updateData];
}
Hey Caylan,
So are you calling insertItemAtIndex on the same flowLayout that you're calling updateData on? If so that would definitely cause issues, as insertItemAtIndex does its calculation of where to insert the item, and essentially calls updateData on its self. If during that phase, while its animating, it in turns gets another updateData call, you could wind up in a bad state. If you're not expecting the insertion to animate, you could set the transitonDuration property to zero, which may stop the issue from occurring.
Is there anyway you can send me the sample that shows this issue happening?
-SteveZ
Not easily... but I'm tracking down the code smell that led me to updateData being called in viewWillAppear.
If I get a FRC call for didChangeObject with changeType NSFetchedResultsChangeMove, what's the preferred way to "move" the cells programmatically?
Looking for something similar to UITableViewController's
... moveRowAtIndexPath:indexPath toIndexPath:newIndexPath];
Alternatively, I can call "updateData" and that seems to do the trick. The flowView is in the background, so I'm not worried about animations. However, a future split-view may be in the cards, which would mean a left-side tableView that represents the flow cells, and the table view may be edited/reordered which should then show the movement of the cells on the right-side.
The FlowLayoutView doesn't currently have an equivalent move through code.
Just insert/remove and update(which is to animate resizing).
So the only way to really do a move is to basically just update your underlying data, and just call updateData, it wouldn't animate though.
We could definitely add that as a feature though, it just wasn't added originally, b/c of time, and we weren't sure how many people would actually use it. For example the IGGridView has the same methods as the UITableview, however i don't think it's ever actually been used :), at least no one has ever asked a support question around it.
I spoke too soon. This may be a chicken and egg scenario.
When I use the flowLayout itself to move a cell, it calls moveItemAtIndex which lets me update core data. Then, the FRC invokes two didChangeObject updates with NSFetchedResultsChangeMove. For sake of brevity, lets say the two calls are a) 0-->1 and b) 1-->0 where indexPath-->newIndexPath.
When I use updateData on the flowView for NSFetchedResultsChangeMove, I get some pretty serious lag. When I use updateItemAtIndex:newIndexPath.row on the flowView, i get new sizes, but the cells are not refreshed with the correct indexed data.
What's the best way to tell individual cells to reload their views from the data source?