UIMenuController for a UITextView in UITableViewCell calls -tableView:canPerformAction:forRowAtIndexPath: resulting in a crash for some UIMenuItems

Originator:guillaume.algis
Number:rdar://31040407 Date Originated:2017-03-14
Status:Open Resolved:
Product:iOS + SDK Product Version:10.2.x
Classification: Reproducible:Always
 
Summary:
When having a UITextView in a UITableViewCell and long pressing the UITextView, the copy/paste menu has items that should not be shown. For example, it is possible for the menu to have a "Cut" or "Copy" item even if the UITextView is empty or no text is selected (which makes no sense).

This only happens when implementing the following UITableViewDelegate methods:
  -tableView:shouldShowMenuForRowAtIndexPath:
  -tableView:canPerformAction:forRowAtIndexPath:withSender:
  -tableView:performAction:forRowAtIndexPath:withSender:

Note that even if -tableView:shouldShowMenuForRowAtIndexPath: returns NO, -tableView:canPerformAction:forRowAtIndexPath:withSender: will still be called when long-touching the UITextView (?!) and if the latter returns YES, the items will appear in the menu.

When an item which should no be here ("Cut" or "Copy" for example in a empty UITextView) is touched, the app enters an infinite recursion, and crashes.

Stack trace of the crash is attached.


Steps to Reproduce:
Using the attached sample project:
1. Build & run the project
2. Long touch on the light-violet text view in the first cell
3. Tap the "Cut" button in the appearing menu

From scratch:
1. Add a UITextView to a UITableViewCell
2. Implement the following methods in the tableview's delegate:
  -tableView:shouldShowMenuForRowAtIndexPath:
  -tableView:canPerformAction:forRowAtIndexPath:withSender:
  -tableView:performAction:forRowAtIndexPath:withSender:
3. Make -tableView:canPerformAction:forRowAtIndexPath:withSender: return `YES`
4. Build & run
5. Build & run the project
6. Long touch on the light-violet text view in the first cell
7. Tap the "Cut" button in the appearing menu


Expected Results:
The tableview's delegate methods are not called, and the textview menu only show relevant items.

Actual Results:
The tableview's delegate methods are called, wrong menu items are displayed, some of them resulting in the app crashing when tapped.

Regression:
Behavior observed on iOS 10.2.x, on an iPad Mini 4 and an iPhone 7

Notes:
Attached are a minimal sample project demonstrating the problem, and a crashlog after tapping one of the bogus menu items.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!