Using a Webview in a modal NSSheet - objective-c

I am having an issue similiar to this SO question. I would like to have a webview in an NSSheet in which I am doing some authentication to retrieve an API token.
I created a new NSWindowController subclass with a corresponding xib file. This is how I am starting the NSSheet:
- (IBAction)startAuthentication:(NSButton *)sender {
self.authController = [[AuthenticationWindowController alloc] initWithWindowNibName:#"AuthenticationWindow"];
[[NSApplication sharedApplication] beginSheet:self.authController.window
modalForWindow:[self.exportManager window]
modalDelegate:self
didEndSelector:#selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:nil];
}
In the windowDidLoad callback of this authenticationWindowController I am directing the webview to the URL:
- (void)windowDidLoad
{
[super windowDidLoad];
[[self.webView mainFrame]loadRequest:[NSURLRequest requestWithURL:authURL]];
}
It looks great at first sight: if I press the button, the startAuthentication action method is called and the new window is animated into the parent window and the authURL is loaded. The website is displayed correctly with its HTML form containing two input fields (username and password).
The problem is, that I can click on the page and it works, however if I am trying to click into one textfield, so that this field gets focus it does not work. No cursor appears in the text field of the website's form and after each keystroke I hear the NSBeep() sound.
I did some research on this topic and I found two references:
How do I use a WebView in a modal dialog?
Cocoa topics: the case of the modal WebView
What kind of puzzles me is that there is the Facebook Exporter for Aperture Plugin, which shows exactly what I want: a webview in a modal sheet. However I cannot find out what they are making differently . In the Facebook Exporter I have not found any code interacting with the run loops directly.
My questions
Is this a known problem with webviews in modal sheets?
Are the problems explained in the two references still there?
How can I get this working? I do not understand when to switch the runloop mode for example.

there is no general problem with this and I just tried it out again. must be some code besides this? can you narrow it down to the sheet? btw: my sample:
https://dl.dropbox.com/u/3753090/test2.zip
BUT all that said, modal runmode and webviews / timers / networking isnt very waterproof :)
because: when you go modal via one of the convenience methods in NSApp, the runloop is only run in a very limited way. :/

Related

Where is my closed NSWindow?

I have an Application delegate that holds the reference to a NSWindow and the program (small test program so far) is generally working with Main Menu and views in the window.
However I discovered that if I close the window holding the views it's gone although the program is still running. As far as i can see the window reference is not nil but how do I restore it so it's visible and shown under the Windows menu again?
The program is not document based. All actions are performed in the window in question.
I created the window in the MainMenu.xib that was auto created by Xcode (this was in Xcode7 or 8 but now I've upgraded to 9).
I'm new to windows handling on Mac so I understand this is a very basic question but I'm totally stuck here. Having a window that is supposed to hold all functionality disappear without the user being able to restore it is bad I believe.
If you have a reference to the NSWindow, you just need to show it. For example:
[window makeKeyAndOrderFront:self];
But if the user closed the single window of your app, than the question is: How will the user trigger that code? The simplest answer is that the user will click your app's icon on the dock. To handle that click, implement the following method on you app delegate.
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)hasVisibleWindows
{
if (hasVisibleWindows) {
return YES;
}
[window makeKeyAndOrderFront:self];
return NO;
}

UITextField losing firstResponder after view appears

I have a UIPageViewController. One page has a single button, and the other page has a UITextField with a button. When the page scrolls to the view with the field, I'd like it to becomeFirstResponder and open the keyboard. Here's what happens:
I call [self.locationQuery becomeFirstResponder] ViewController's viewDidAppear method. But it never opens the keyboard.
I do the same in viewWillAppear, and it appears briefly, but then is quickly dismissed.
If I'm on the page with the text field, and pull the page partway and let it go (without changing pages), self.locationQuery receives focus just fine.
It seems like something else is grabbing firstResponder status from the field, but I haven't the faintest idea what, and why it would only be happening when the page changed (rather than revealed after a failed page turn). Any ideas?
Update
I created a way to crawl the views to see if any other views were, indeed, taking firstResponder (from an answer to this question: Get the current first responder without using a private API). Results:
When I explicitly give first responder to the text field, the method reports it has first responder status.
When I don't, it returns null.
Now I'm even more confused.
I don't really understand the nature of what was causing my issue, but I was able to fix it by wrapping the call in an async dispatch in viewDidAppear:
dispatch_async(dispatch_get_main_queue(), ^{
MapManualViewController *strongSelf = weakSelf;
[strongSelf.locationQuery becomeFirstResponder];
});
This one stole a few hours from my life. Here is the Swift 3.x implementation.
DispatchQueue.main.async(execute: {() -> Void in
let strongSelf: MapManualViewController = self
strongSelf. textField.becomeFirstResponder()
})
I also put it in viewDidAppear

NSDocument display name of page with WebKit

I'm trying to get WebKit to display the page title of the currently opened document window, which includes a WebView. The document won't display after I run the app.
I'm using Document.m and windowNibName to achieve this, but I'm sure what I'm doing is wrong. I think it might be with both the NSStrings, which I can't have. Though if I don't have them I can't return the Document title... (WebKit/WebKit.h is imported)
- (NSString)windowNibName:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
{
// Report feedback only for the main frame.
if (frame == [sender mainFrame]){
[[sender window] setTitle:title];
}
return #"Document";
}
You've implemented a method named windowNibName:didReceiveTitle:forFrame:, but nothing sends such a message (unless you are, but if you are, you left that code out).
The correct method name is webView:didReceiveTitle:forFrame:. Assuming you only have one web view in the window and only one window in the document, and assuming that the document is the web view's delegate, you can simply set the document's display name from there.
If you have something more complex going on, with multiple web views per window and/or multiple windows per document, then you'll need to ask the web view for its window, the window for its window controller, and the window controller for its document, and then set the document's display name as above.
Also, windowNibName has nothing to do with setting the document's title to the web page's title. The web view probably hasn't even started to load a page yet, if it even has a URL to load at all. That's why you need to be the web view's delegate and respond to that delegate message.

iOS Objective-C: Unbalanced calls to begin/end appearance transitions for <GKModalRootViewController>

I was hoping someone would be able to answer my question.
In my app I have a button you can press that takes you a leaderboard I have created. In the sandbox environment, the first time a user clicks on this the user is asked to sign in - with an existing account or a new account.
If a user clicks on use existing account, after verifying their username, password, GameCenter display name and so forth, when the screen closes to go back to the screen with the leaderboard button - none of the buttons will now respond. The user is forced to quit the app (and the instance through the double-click of the home button) and reopen the app, where now they can play as usual and even click on the leaderboard with no problems.
I was wondering why this was, and the only clue I seem to have is through the output screen in Xcode which says while running:
ClubHistory[4989:707] Unbalanced calls to begin/end appearance transitions for <GKModalRootViewController: 0x1bcd90>.
From looking up other questions it seems this might mean a clash of opening/closing views. But I don't really understand where I should implement this.
Part of the code which opens the leaderboard in the first instance is:
-(void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController
{
[self dismissModalViewControllerAnimated:YES];
}
-(IBAction ) showLeaderboard
{
GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc]init];
if (leaderboardController != NULL)
{
leaderboardController.category = self.currentLeaderBoard;
leaderboardController.timeScope = GKLeaderboardTimeScopeWeek;
leaderboardController.leaderboardDelegate = self;
[self presentModalViewController: leaderboardController animated:YES];
}
}
Perhaps the alteration I need to make is made here.
I had a look online for similar problems to no avail. Does anyone know how I can solve this issue?
Thanks everyone,
Andy.
///// Quick edit: Just to clarify I have ARC turned on for my app.
[...] the first time a user clicks on this the user is asked to sign in - with an existing account or a new account
How are you presenting this interface for the user to sign in? Is it also a Modal View Controller? If this is the case, maybe you're not presenting and dismissing these two Modal View Controllers properly. From Apple's docs:
Any view controller object can present a single view controller at a time.
Try dismissing the View Controller with the sign in interface before presenting the GKLeaderboardViewController.

Can I hide the Action button on the UIDocumentInteractionController view?

I wanted to know if I can hide the Action button on the UIDocumentInteractionController so a user couldn't actually open the document in another app?
I found something that works for me well enough:
- (BOOL)documentInteractionController:(UIDocumentInteractionController *)controller canPerformAction:(SEL)action{
return false;
}
It still shows the button but the popover that appears only has the print form but the print button is disabled.
The whole purpose of the UIDocumentInteractionController is to show the user which applications can handle a file and give them a way to 'send' the file to the app they choose. Since hiding/disabling the button would confuse the user, I doubt it is possible (at least not without resorting to undocumented method calls).