Is this a bug in AppDelegate?


Peter Teeson
 

macOS Yosemite 10.10.5; Xcode 6.4
In testing a vanilla Document app I tracked down what may be a bug in Cocoa.

I expected that the app would not open an untitled file because
applicationOpenUntitledFile returned NO. 
But an untitled file was in fact opened in a window.

OTOH if I change applicationShouldOpenUntitledFile return to NO then 
no file is opened and the app launches without a window, just a menu bar.

So is it a bug or is my expectation incorrect? 

- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
    // Use this method to decide whether the application should open a new, untitled file.
    // Note that applicationOpenUntitledFile: is invoked if this method returns YES.

    

    return YES; // YES if the application should open a new untitled file or NO if it should not.
}

- (BOOL)applicationOpenUntitledFile:(NSApplication *)theApplication {
    // Sent directly by theApplication to the delegate to request that a new, untitled file be opened.

    

    return NO; // YES if the file was successfully opened or NO if it was not.
}


Quincey Morris
 

On Aug 4, 2018, at 22:30 , Peter Teeson via Groups.Io <peter.teeson@...> wrote:

I expected that the app would not open an untitled file because
applicationOpenUntitledFile returned NO. 
But an untitled file was in fact opened in a window.

I can’t swear to it, but I’m pretty certain this is a result of state restoration. Assuming you had at some previous point created an untitled window, then state restoration will recreate it at next launch, without going through applicationOpenUntitledFile — because it’s not really creating a new document, but re-opening an autosaved one, which just happens to be called “Untitled”.

Try running it with the scheme option to prevent state restoration, and I suspect you’ll see the expected behavior.


Peter Teeson
 

I can’t swear to it, but I’m pretty certain this is a result of state restoration
Good idea… However I just did this:
1. created a new document project
2. added to AppDelegate.m
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
    // Use this method to decide whether the application should open a new, untitled file.
    // Note that applicationOpenUntitledFile: is invoked if this method returns YES.
    
    return YES// YES if the application should open a new untitled file or NO if it should not.
}

- (BOOL)applicationOpenUntitledFile:(NSApplication *)theApplication {
    // Sent directly by theApplication to the delegate to request that a new, untitled file be opened.
    
    return NO// YES if the file was successfully opened or NO if it was not.
}
3. compiled and ran it with Run option "Launch application without state restoration”. 
Same result. There never was a previously saved untitled window.
But an untitled window was created even though I returned NO in applicationOpenUntitledFile.
Debugger showed:

2018-08-05 15:24:51.511 TestBug[12185:1447476] ApplePersistenceIgnoreState: 
Existing state will not be touched. 
New state will be written to /var/folders/w1/081y692x5x30c39mcr8lxwkh0000gn/T/phtSW.TestBug.savedState

What else could it be? 

On Aug 5, 2018, at 2:10 AM, Quincey Morris <quinceymorris@...> wrote:

On Aug 4, 2018, at 22:30 , Peter Teeson via Groups.Io <peter.teeson@...> wrote:

I expected that the app would not open an untitled file because
applicationOpenUntitledFile returned NO. 
But an untitled file was in fact opened in a window.

I can’t swear to it, but I’m pretty certain this is a result of state restoration. Assuming you had at some previous point created an untitled window, then state restoration will recreate it at next launch, without going through applicationOpenUntitledFile — because it’s not really creating a new document, but re-opening an autosaved one, which just happens to be called “Untitled”.

Try running it with the scheme option to prevent state restoration, and I suspect you’ll see the expected behavior.



Bill Pitcher
 

Hi Peter,

I think you have the flow here a little confused.

func applicationShouldOpenUntitledFile(_ sender: NSApplication) -> Bool
lets the App know if there is going to be an Untiled Document, false neither the App Default nor the applicationOpenUntitledFile will be called. (Watch out that it doesn’t load an already created one automatically.)

IF applicationShouldOpenUntitledFile returns TRUE

func applicationOpenUntitledFile(_ sender: NSApplication) -> Bool
This gives the delegate an opportunity to create an Untitled Document

Returning true from this tells the App that you have taken responsibility for creating the Untiled document and that it shouldn’t.
Return false at this point tells the App applicationOpenUntitledFile didn't create the Untiled Document and that it should make the default Untitled

That’s my take on it, hope it helps.
cheers
Bill Pitcher
Tutor
Literacy Aotearoa - Dunedin

On 6/08/2018, at 7:35 AM, Peter Teeson via Groups.Io <peter.teeson=icloud.com@groups.io> wrote:

I can’t swear to it, but I’m pretty certain this is a result of state restoration
Good idea… However I just did this:
1. created a new document project
2. added to AppDelegate.m
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
// Use this method to decide whether the application should open a new, untitled file.
// Note that applicationOpenUntitledFile: is invoked if this method returns YES.

return YES; // YES if the application should open a new untitled file or NO if it should not.
}

- (BOOL)applicationOpenUntitledFile:(NSApplication *)theApplication {
// Sent directly by theApplication to the delegate to request that a new, untitled file be opened.

return NO; // YES if the file was successfully opened or NO if it was not.
}
3. compiled and ran it with Run option "Launch application without state restoration”.
Same result. There never was a previously saved untitled window.
But an untitled window was created even though I returned NO in applicationOpenUntitledFile.
Debugger showed:

2018-08-05 15:24:51.511 TestBug[12185:1447476] ApplePersistenceIgnoreState:
Existing state will not be touched.
New state will be written to /var/folders/w1/081y692x5x30c39mcr8lxwkh0000gn/T/phtSW.TestBug.savedState

What else could it be?

On Aug 5, 2018, at 2:10 AM, Quincey Morris <quinceymorris@rivergatesoftware.com> wrote:

On Aug 4, 2018, at 22:30 , Peter Teeson via Groups.Io <peter.teeson=icloud.com@groups.io> wrote:

I expected that the app would not open an untitled file because
applicationOpenUntitledFile returned NO.
But an untitled file was in fact opened in a window.
I can’t swear to it, but I’m pretty certain this is a result of state restoration. Assuming you had at some previous point created an untitled window, then state restoration will recreate it at next launch, without going through applicationOpenUntitledFile — because it’s not really creating a new document, but re-opening an autosaved one, which just happens to be called “Untitled”.

Try running it with the scheme option to prevent state restoration, and I suspect you’ll see the expected behavior.


Peter Teeson
 

Hi Bill. Thanks for your (Swift) reply <grin>. You may be correct in how the flow works.
Mind you I have not found any documentation to support it; can you point me to some?

I was basing my assumption on the Xcode Documentation and API reference.
(That’s why I put those comments in the skeleton method implementations)

Basically I inferred the classic truth table:
Should open NO  NO YES YES
OpenUntitled NO YES NO YES

Open Window NO NO NO YES Expected
Open Window NO NO YES NO Actual

These tests were all launched with Run option "Launch application without state restoration”.

 FWIW

Peter


On Aug 5, 2018, at 5:02 PM, Bill Pitcher <bill@...> wrote:

Hi Peter,

I think you have the flow here a little confused.

func applicationShouldOpenUntitledFile(_ sender: NSApplication) -> Bool
lets the App know if there is going to be an Untiled Document, false neither the App Default nor the applicationOpenUntitledFile will be called. (Watch out that it doesn’t load an already created one automatically.)

IF applicationShouldOpenUntitledFile returns TRUE

func applicationOpenUntitledFile(_ sender: NSApplication) -> Bool
This gives the delegate an opportunity to create an Untitled Document

Returning true from this tells the App that you have taken responsibility for creating the Untiled document and that it shouldn’t.
Return false at this point tells the App applicationOpenUntitledFile didn't create the Untiled Document and that it should make the default Untitled

That’s my take on it, hope it helps.
cheers
Bill Pitcher
Tutor
Literacy Aotearoa - Dunedin




On 6/08/2018, at 7:35 AM, Peter Teeson via Groups.Io <peter.teeson@...> wrote:

I can’t swear to it, but I’m pretty certain this is a result of state restoration
Good idea… However I just did this:
1. created a new document project
2. added to AppDelegate.m
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
   // Use this method to decide whether the application should open a new, untitled file.
   // Note that applicationOpenUntitledFile: is invoked if this method returns YES.

   return YES; // YES if the application should open a new untitled file or NO if it should not.
}

- (BOOL)applicationOpenUntitledFile:(NSApplication *)theApplication {
   // Sent directly by theApplication to the delegate to request that a new, untitled file be opened.

   return NO; // YES if the file was successfully opened or NO if it was not.
}
3. compiled and ran it with Run option "Launch application without state restoration”. 
Same result. There never was a previously saved untitled window.
But an untitled window was created even though I returned NO in applicationOpenUntitledFile.
Debugger showed:

2018-08-05 15:24:51.511 TestBug[12185:1447476] ApplePersistenceIgnoreState: 
Existing state will not be touched. 
New state will be written to /var/folders/w1/081y692x5x30c39mcr8lxwkh0000gn/T/phtSW.TestBug.savedState

What else could it be? 

On Aug 5, 2018, at 2:10 AM, Quincey Morris <quinceymorris@...> wrote:

On Aug 4, 2018, at 22:30 , Peter Teeson via Groups.Io <peter.teeson@...> wrote:

I expected that the app would not open an untitled file because
applicationOpenUntitledFile returned NO. 
But an untitled file was in fact opened in a window.

I can’t swear to it, but I’m pretty certain this is a result of state restoration. Assuming you had at some previous point created an untitled window, then state restoration will recreate it at next launch, without going through applicationOpenUntitledFile — because it’s not really creating a new document, but re-opening an autosaved one, which just happens to be called “Untitled”.

Try running it with the scheme option to prevent state restoration, and I suspect you’ll see the expected behavior.







Bill Pitcher
 

Sorry, I'll try and be more Objective.

Working back in Aqua 10.0 there was no documentation, LOL and we had to read the message names and headers to get an understanding of this NextStep puzzle. With these very very old Objects, you'll need to base your assumption on trying to understand the mindset of the API more than the documentation.

The key word is Should, a method with Should in it's name is to allow/stop something from happening. Application Should Open Untiled File, return YES and the Application Should open an untiled File, NO and it Should not. It's the switch "Invoked immediately before opening an untitled file." to determine if the untitled file should be created at all. This comes before the...

At this point there are 2 ways the Application can Open an Untitled File, the first is without Delegate intervention. The Application can instigate an NSDocument and wire up the Controllers and Window automagicly, OR the Delegate gets to do it, by implementing the applicationOpenUntitledFile message which is "Sent directly by theApplication to the delegate to request that a new, untitled file be opened.". This is the Delegate's opportunity to do all the heavy lifting and make any changes to the default behaviour. This Delegate message needs to report back to the Application "YES if the file was successfully opened or NO if it was not." if YES, all is good, end of story. If NO, and this I think is where you are surprised, Because you have told the Application YES we must have an Untiled File, but the Delegate has reported NO I haven't been successful making one, the Application knows it needs to make an Untiled File, so it continues on to make it's default Untiled File.

In the Flow applicationShouldOpenUntitledFile returning NO stops the flow, else we detour to the Delegate to see if it can create Untiled in applicationOpenUntitledFile, was the Delegate successful YES stops the Flow, NO back to the App which now makes the Untitled File.

https://developer.apple.com/library/archive/documentation/DataManagement/Conceptual/DocBasedAppProgrammingGuideForOSX/AdvancedTopics/AdvancedTopics.html#//apple_ref/doc/uid/TP40011179-CH7-SW6

Down the page, Message Flow in the Document Architecture, does NOT show the Application process but it illustrates this Flow idea for Documents, a chart like this for App startup would be nice. "This message flow provides many opportunities for you to customize the behavior of your app by overriding methods"

I'm sorry if this seem a bit pedantic but trust me the Objects that came with Next have a distinct flavor/idiom and the best way to understand them is read the documentation in this idiom. If you don't get the expected results, do exactly what you have done, make a TestApp, try the options then re-read the documentation with this new understanding, and trying to understand the idiom, After 20yrs the documentation is "Generally" correct.

I think Apple will not be changing how 10.0 Objects function, at best a bug report might get a change in documentation, but on something this old and the upcoming move to UIKit I wouldn't think so.

Hope this helps with your journey back into the past;-) old documentation links below.

cheers
Bill

https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Introduction.html#//apple_ref/doc/uid/TP40008195-CH68-DontLinkElementID_2

https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html#//apple_ref/doc/uid/TP40008195-CH14

https://www.cocoawithlove.com/2009/06/method-names-in-objective-c.html

Bill Pitcher
Tutor
Literacy Aotearoa - Dunedin

On 8/08/2018, at 8:07 AM, Peter Teeson via Groups.Io <peter.teeson=icloud.com@groups.io> wrote:

Hi Bill. Thanks for your (Swift) reply <grin>. You may be correct in how the flow works.
Mind you I have not found any documentation to support it; can you point me to some?

I was basing my assumption on the Xcode Documentation and API reference.
(That’s why I put those comments in the skeleton method implementations)

Basically I inferred the classic truth table:
Should open NO NO YES YES
OpenUntitled NO YES NO YES

Open Window NO NO NO YES Expected
Open Window NO NO YES NO Actual

These tests were all launched with Run option "Launch application without state restoration”.

FWIW

Peter


On Aug 5, 2018, at 5:02 PM, Bill Pitcher <bill@ilike.co.nz> wrote:

Hi Peter,

I think you have the flow here a little confused.

func applicationShouldOpenUntitledFile(_ sender: NSApplication) -> Bool
lets the App know if there is going to be an Untiled Document, false neither the App Default nor the applicationOpenUntitledFile will be called. (Watch out that it doesn’t load an already created one automatically.)

IF applicationShouldOpenUntitledFile returns TRUE

func applicationOpenUntitledFile(_ sender: NSApplication) -> Bool
This gives the delegate an opportunity to create an Untitled Document

Returning true from this tells the App that you have taken responsibility for creating the Untiled document and that it shouldn’t.
Return false at this point tells the App applicationOpenUntitledFile didn't create the Untiled Document and that it should make the default Untitled

That’s my take on it, hope it helps.
cheers
Bill Pitcher
Tutor
Literacy Aotearoa - Dunedin




On 6/08/2018, at 7:35 AM, Peter Teeson via Groups.Io <peter.teeson=icloud.com@groups.io> wrote:

I can’t swear to it, but I’m pretty certain this is a result of state restoration
Good idea… However I just did this:
1. created a new document project
2. added to AppDelegate.m
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
// Use this method to decide whether the application should open a new, untitled file.
// Note that applicationOpenUntitledFile: is invoked if this method returns YES.

return YES; // YES if the application should open a new untitled file or NO if it should not.
}

- (BOOL)applicationOpenUntitledFile:(NSApplication *)theApplication {
// Sent directly by theApplication to the delegate to request that a new, untitled file be opened.

return NO; // YES if the file was successfully opened or NO if it was not.
}
3. compiled and ran it with Run option "Launch application without state restoration”.
Same result. There never was a previously saved untitled window.
But an untitled window was created even though I returned NO in applicationOpenUntitledFile.
Debugger showed:

2018-08-05 15:24:51.511 TestBug[12185:1447476] ApplePersistenceIgnoreState:
Existing state will not be touched.
New state will be written to /var/folders/w1/081y692x5x30c39mcr8lxwkh0000gn/T/phtSW.TestBug.savedState

What else could it be?

On Aug 5, 2018, at 2:10 AM, Quincey Morris <quinceymorris@rivergatesoftware.com> wrote:

On Aug 4, 2018, at 22:30 , Peter Teeson via Groups.Io <peter.teeson=icloud.com@groups.io> wrote:

I expected that the app would not open an untitled file because
applicationOpenUntitledFile returned NO.
But an untitled file was in fact opened in a window.
I can’t swear to it, but I’m pretty certain this is a result of state restoration. Assuming you had at some previous point created an untitled window, then state restoration will recreate it at next launch, without going through applicationOpenUntitledFile — because it’s not really creating a new document, but re-opening an autosaved one, which just happens to be called “Untitled”.

Try running it with the scheme option to prevent state restoration, and I suspect you’ll see the expected behavior.


Peter Teeson
 

Hi Bill:

Thanks very much for the explanation and especially links to where the old docs are.
I remember the loos leaf docs and the excellent Inside Mac books and the docs you linked to.
Just couldn’t find them and din’t think to look for an archive.

WRT reading header etc to figure things out… in the “good old days” it was that plus the local folklore….

Thanks again for your guidance…

respect…

Peter

On Aug 7, 2018, at 6:34 PM, Bill Pitcher <bill@ilike.co.nz> wrote:

Sorry, I'll try and be more Objective.

Working back in Aqua 10.0 there was no documentation, LOL and we had to read the message names and headers to get an understanding of this NextStep puzzle. With these very very old Objects, you'll need to base your assumption on trying to understand the mindset of the API more than the documentation.

The key word is Should, a method with Should in it's name is to allow/stop something from happening. Application Should Open Untiled File, return YES and the Application Should open an untiled File, NO and it Should not. It's the switch "Invoked immediately before opening an untitled file." to determine if the untitled file should be created at all. This comes before the...

At this point there are 2 ways the Application can Open an Untitled File, the first is without Delegate intervention. The Application can instigate an NSDocument and wire up the Controllers and Window automagicly, OR the Delegate gets to do it, by implementing the applicationOpenUntitledFile message which is "Sent directly by theApplication to the delegate to request that a new, untitled file be opened.". This is the Delegate's opportunity to do all the heavy lifting and make any changes to the default behaviour. This Delegate message needs to report back to the Application "YES if the file was successfully opened or NO if it was not." if YES, all is good, end of story. If NO, and this I think is where you are surprised, Because you have told the Application YES we must have an Untiled File, but the Delegate has reported NO I haven't been successful making one, the Application knows it needs to make an Untiled File, so it continues on to make it's default Untiled File.

In the Flow applicationShouldOpenUntitledFile returning NO stops the flow, else we detour to the Delegate to see if it can create Untiled in applicationOpenUntitledFile, was the Delegate successful YES stops the Flow, NO back to the App which now makes the Untitled File.

https://developer.apple.com/library/archive/documentation/DataManagement/Conceptual/DocBasedAppProgrammingGuideForOSX/AdvancedTopics/AdvancedTopics.html#//apple_ref/doc/uid/TP40011179-CH7-SW6

Down the page, Message Flow in the Document Architecture, does NOT show the Application process but it illustrates this Flow idea for Documents, a chart like this for App startup would be nice. "This message flow provides many opportunities for you to customize the behavior of your app by overriding methods"

I'm sorry if this seem a bit pedantic but trust me the Objects that came with Next have a distinct flavor/idiom and the best way to understand them is read the documentation in this idiom. If you don't get the expected results, do exactly what you have done, make a TestApp, try the options then re-read the documentation with this new understanding, and trying to understand the idiom, After 20yrs the documentation is "Generally" correct.

I think Apple will not be changing how 10.0 Objects function, at best a bug report might get a change in documentation, but on something this old and the upcoming move to UIKit I wouldn't think so.

Hope this helps with your journey back into the past;-) old documentation links below.

cheers
Bill

https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Introduction.html#//apple_ref/doc/uid/TP40008195-CH68-DontLinkElementID_2

https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html#//apple_ref/doc/uid/TP40008195-CH14

https://www.cocoawithlove.com/2009/06/method-names-in-objective-c.html

Bill Pitcher
Tutor
Literacy Aotearoa - Dunedin




On 8/08/2018, at 8:07 AM, Peter Teeson via Groups.Io <peter.teeson=icloud.com@groups.io> wrote:

Hi Bill. Thanks for your (Swift) reply <grin>. You may be correct in how the flow works.
Mind you I have not found any documentation to support it; can you point me to some?

I was basing my assumption on the Xcode Documentation and API reference.
(That’s why I put those comments in the skeleton method implementations)

Basically I inferred the classic truth table:
Should open NO NO YES YES
OpenUntitled NO YES NO YES

Open Window NO NO NO YES Expected
Open Window NO NO YES NO Actual

These tests were all launched with Run option "Launch application without state restoration”.

FWIW

Peter


On Aug 5, 2018, at 5:02 PM, Bill Pitcher <bill@ilike.co.nz> wrote:

Hi Peter,

I think you have the flow here a little confused.

func applicationShouldOpenUntitledFile(_ sender: NSApplication) -> Bool
lets the App know if there is going to be an Untiled Document, false neither the App Default nor the applicationOpenUntitledFile will be called. (Watch out that it doesn’t load an already created one automatically.)

IF applicationShouldOpenUntitledFile returns TRUE

func applicationOpenUntitledFile(_ sender: NSApplication) -> Bool
This gives the delegate an opportunity to create an Untitled Document

Returning true from this tells the App that you have taken responsibility for creating the Untiled document and that it shouldn’t.
Return false at this point tells the App applicationOpenUntitledFile didn't create the Untiled Document and that it should make the default Untitled

That’s my take on it, hope it helps.
cheers
Bill Pitcher
Tutor
Literacy Aotearoa - Dunedin




On 6/08/2018, at 7:35 AM, Peter Teeson via Groups.Io <peter.teeson=icloud.com@groups.io> wrote:

I can’t swear to it, but I’m pretty certain this is a result of state restoration
Good idea… However I just did this:
1. created a new document project
2. added to AppDelegate.m
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
// Use this method to decide whether the application should open a new, untitled file.
// Note that applicationOpenUntitledFile: is invoked if this method returns YES.

return YES; // YES if the application should open a new untitled file or NO if it should not.
}

- (BOOL)applicationOpenUntitledFile:(NSApplication *)theApplication {
// Sent directly by theApplication to the delegate to request that a new, untitled file be opened.

return NO; // YES if the file was successfully opened or NO if it was not.
}
3. compiled and ran it with Run option "Launch application without state restoration”.
Same result. There never was a previously saved untitled window.
But an untitled window was created even though I returned NO in applicationOpenUntitledFile.
Debugger showed:

2018-08-05 15:24:51.511 TestBug[12185:1447476] ApplePersistenceIgnoreState:
Existing state will not be touched.
New state will be written to /var/folders/w1/081y692x5x30c39mcr8lxwkh0000gn/T/phtSW.TestBug.savedState

What else could it be?

On Aug 5, 2018, at 2:10 AM, Quincey Morris <quinceymorris@rivergatesoftware.com> wrote:

On Aug 4, 2018, at 22:30 , Peter Teeson via Groups.Io <peter.teeson=icloud.com@groups.io> wrote:

I expected that the app would not open an untitled file because
applicationOpenUntitledFile returned NO.
But an untitled file was in fact opened in a window.
I can’t swear to it, but I’m pretty certain this is a result of state restoration. Assuming you had at some previous point created an untitled window, then state restoration will recreate it at next launch, without going through applicationOpenUntitledFile — because it’s not really creating a new document, but re-opening an autosaved one, which just happens to be called “Untitled”.

Try running it with the scheme option to prevent state restoration, and I suspect you’ll see the expected behavior.