问题
In Document-Based Apps, using XIB files, when a new window is created its behaviour is:
- Be positioned and sized based on the position of the last active window.
- If the last active window is still visible then the new window should be cascaded so it doesn't directly overlap.
However when using a storyboard this isn't done. See test project.
回答1:
You can set shouldCascadeWindows on the window controller in your storyboard:
- select the window controller in the storyboard
- select the identity inspector
- add a new User Defined Runtime Attribute with these values:
- key path: shouldCascadeWindows
- Type: boolean
- Value: checked
Update: If you move the first window, new windows cascade starting in the middle of the screen not under the first window. To fix it:
- select the window
- in the attributes inspector give it an autosave name
This should also persist window location and size on the next window load and application launch.
回答2:
Cascaded Windows Problem
One of the problems is that storyboards unlike xibs can include the NSWindowController
and Interface Builder doesn't serialize it right.
-initWithWindow:
, -initWithWindowNibName:
and friends set shouldCascadeWindows
to YES
.
When a NSWindowController
is loaded from a storyboard via -initWithCoder:
, shouldCascadeWindows
is NO
. (OS X 10.11)
Based on my tests, this property needs to be set in the initializer. Setting it in -[NSDocument addWindowController:]
didn't work. (OS X 10.11)
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self)
{
self.shouldCascadeWindows = YES;
}
return self;
}
See rdar://47350352
Window Position Problem
Using -[NSWindowController windowFrameAutosaveName]
or -[NSWindow frameAutosaveName]
seems only to work sometimes. Randomly it uses the initial window position.
Window Size Problem
Even if the cascaded window position is set right, it never set the size to the one saved for the frame. I verified the saved frame with defaults read window.autosavename.test1
. Also before each test I run defaults delete window.autosavename.test1
for a clean state.
Workaround
Use a xib containing a empty NSWindow
and add the view controllers from the storyboard in -[NSDocument windowControllerDidLoadNib:
or -[NSDocument addWindowController:]
to the window.
回答3:
I think the answer might be that it's just not possible to have multiple windows share the same frameAutosaveName
even though it is possible to have multiple NSSplitView share the same autosaveName
.
I just tried creating another NSDocument based project, but this time I used xib's instead of a storyboard. The behavior is better (shouldCascadeWindows
is on by default). But new window positioning still breaks down when multiple windows are involved.
I think this is more of a runtime constraint then it is storyboard vrs xib problem. Here's a test I just did in the default non storyboard NSDocument project generated by Xcode:
Set window autosave name in interface builder.
Modify
windowControllerDidLoadNib
to look like this:- (void)windowControllerDidLoadNib:(NSWindowController *)aController { [super windowControllerDidLoadNib:aController]; NSLog(@"Listing frameAutosaveName for all windows:"); for (NSWindow *each in [NSApp windows]) { NSLog(@"%@: %@", each.title, each.frameAutosaveName); } }
And then (after creating a number of windows) this is the output that I see:
Listing frameAutosaveName for all windows: Untitled: SaveMe Untitled 2: Untitled 3: Untitled 4: Untitled 5: Window:
So only the first window created gets the "SaveMe" autosave name. For all the following windows the value is never set.
My conclusion is that you just can't use frameAutosaveName
to replicate Safari's behavior. Instead you must do something manual. I'm not sure if the method used in the example project is the best way, but I think at least some manual work is needed for Safari's behavior no matter if you are using xibs or storyboards.
来源:https://stackoverflow.com/questions/35827239/document-based-app-autosave-with-storyboards