How to detect when an NSTextView has finished being loaded into a window?
How to detect when an NSTextView has finished being loaded into a window?
- Subject: How to detect when an NSTextView has finished being loaded into a window?
- From: Keith Blount <email@hidden>
- Date: Mon, 21 Feb 2011 06:22:35 -0800 (PST)
Hello,
I'm trying to detect when an NSTextView has finished being loaded into its window in a situation where -viewDidMoveToWindow won't work - is there another way of doing this that I'm overlooking?
Here's the situation, and the reason -viewDidMoveToWindow won't work:
I've spent the last week debugging a nasty crashing bug that affected my page layout code in rare circumstances when it was loaded on project open (http://www.cocoabuilder.com/archive/cocoa/298810-tracking-exc-bad-access-when-zombies-don-work.html?q=exc_bad_access#298810 - many thanks to those who helped!). It turned out there were a couple of issues involved, one to do with layout, and the other to do with the timing of the page layout view getting swapped into the window, which is what I'm trying to solve now. This is how things are currently set up:
When a project in my program is opened, a text view is created programmatically. The user can choose whether to view text in a single text view or in a multiple pages view. Thus, in my NSTextView subclass, I have overridden -viewDidMoveToWindow to send out a notification that tells listeners when the text view has finished being moved to a window. I have my controller listen for this notification, and when it detects that the text view has moved to a window, it restores the user's previous settings. One of these settings is whether to use a multiple page (i.e. multiple text container) set up, and if this is set to YES then the text view gets swapped out and replaced with the page layout view.
(The reason it's done like this, by the way, rather than just creating the page layout view instead of the text view programmatically in the first place, is that it turns out you cannot create a multiple text view and load it with text off-screen. If you do, when you move it on to the screen it will work but you get lots of drawing artefacts, such as the insertion point appearing in multiple places. I had a technical support request out with Apple on this, and it took a good while to work out that the fix was to ensure the page layout view was only created and laid out once everything had been moved to a window. Therefore I wait until the regular single text view - which isn't affected by such artefacts - is safely loaded into a window before trying to swap in the page layout view.)
However, the problem is that it turns out it's not safe to swap out a view from -viewDidMoveToWindow (which I suppose shouldn't come as a big surprise). I had assumed -viewDidMoveToWindow would be final, and that the view would have finished moving to the window and getting set up by the time this method is called, but it's not the case. -viewDidMoveToWindow seems to be called from the private NSView method _setWindow:. NSTextView overrides _setWindow: and calls another private method, -_requestUpdateOfDragTypeRegistration, *after* -viewDidMoveToWindow has been called. -_requestUpdateOfDragTypeRegistration in turn calls -performSelector:withObject:afterDelay: on self (with the selector -updateDragTypeRegistration).
Thus, if I swap out the text view in -viewDidMoveToWindow:, the text view still tries to finish the rest of the _setWindow: method afterwards, and ends up calling -performSelector:withObject:afterDelay: on self after it has been deallocated.
So, I'm trying to find a more final way of only setting up the page view after the window is on screen and everything necessary has been moved to that window, so that the text view has completely finished loading. Overriding _setWindow: and posting the notification at the end of that method works, but obviously that is a private method and if I want to get on the Mac App Store I'm going to need to avoid such solutions. I've also tried only posting the notification after a delay of 0, which works and avoids the crash, but is a little slow - you can see the original text view getting loaded on screen before being swapped for the multiple page view.
By this point, I've probably over-complicated everything and am missing something obvious, so I'd be grateful for any suggestions. (Obviously -awakeFromNib and -windowDidLoad come before anything is guaranteed to be on screen, otherwise I would have used those from the get-go.)
Many thanks and all the best,
Keith
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden