UIResponder.undoManager property returns nil for non-visible view

Originator:azhreifje
Number:rdar://44503625 Date Originated:9/16/2018
Status:Open Resolved:
Product:iOS + SDK Product Version:11.4
Classification:UI/Usability Reproducible:Always
 
Area:
UIKit

Summary:  The documentation for UIResponder.undoManager says that it performs a runtime lookup through views (and controllers) in the view stack, returning the undoManager closest to the visible view.  Yet a closure in a superclass that uses that class's undoManager property returns nil (although viewDidAppear() returns the proper value).

Steps to Reproduce:  Unpack the attached TestProject.zip file.  Execute the project (in the Simulator, for example).

When the main view appears, so do four lines from print() statements.  Note the classes and methods involved.  So far, so good.

Click the first item in the table view and a detail view appears.  A few more lines of output appear; still good.

Click the "<Back" button.  In the detail view's viewWillDisappear() method, a closure created by the prepare() method inherited from the superclass's superclass is invoked and the undoManager is nil.  Why?  The undoManager was non-nil in the same class when viewDidAppear() was invoked.

I have attached the project here, but my GitHub gist also contains the source code, along with the output produced by print(), two images (class diagram and visual representation of the storyboard), and a discussion of what the expected output should look like:  https://gist.github.com/Azhrei/265ce5c12be9e3303239ebdad3a36de0

I used the gist while trying to explain this on forums.developer.apple.com:  https://forums.developer.apple.com/thread/108311?sr=stream

Expected Results:  I expect the closure populated by the superclass prepare() method — that references the superclass undoManager property — to return non-nil.  Otherwise, how can a superclass provide functionality that subclasses can inherit and reuse?  Inheritance *is* the mechanism by which object-oriented languages implement code reuse!

If my expectations are wrong, perhaps there's an example somewhere that demonstrates how to properly use inheritance for VCs along with a nav controller and undoManager?

Actual Results:  undoManager returns nil.

Version/Build:  Latest non-beta of everything:  Xcode 9.4.1, Swift 4.1, iOS Simulator for 11.4 on iPhone 8 Plus (device doesn't matter).

Configuration:  Not sure what information you're looking for here that wouldn't be included in "Version/Build"?

Comments

Based on comments from the developers @ forums.developer.apple.com, I've refactored the code so it uses a delegate instead of a closure. I guess the thinking was that the closure might not be grabbing self properly or something (?). The updated gist contains that new code. But no luck; the problem still exists.


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!