Opening NSSavePanel as sheet - xcode

I am using XCode7 beta2 to play around with Swift 2. Trying to use a File-Selection Dialog (NSSavePanel) brought me into some trouble.
Running the following code by clicking the associated button won't bring up the dialog as a sheet (not at all) but make my window's decoration disappear, leaving it in a broken state where otherwise functional sheets open as dialogs without decoration. Using the call to the deprecated API beginSheetModalForWindow, like in the commented line, works like expected.
#IBAction func openFileClicked(sender: AnyObject) {
let openPanel = NSSavePanel()
openPanel.canCreateDirectories = true
//openPanel.beginSheetModalForWindow(self.view.window!, completionHandler: {
openPanel.beginSheet(self.view.window!, completionHandler: {
(result) -> Void in
print("opening:\(result)" )
})
}
Is my code broken somehow or is there a issue with the API I am calling.

Related

iOS 12 present(fromrootviewcontroller) causes app to freeze

Very confused about an issue I've just stumbled across.
I have a swift game, mainly using SpriteKit.
At the end of a game an ad is loaded. Or when the user decides to end the game an ad is also loaded.
If the game is played normally. The flow is as follows...
MenuScene -> GameScene -> [ad loads] -> GameOverScene
If the user quits the game...
MenuScene -> GameScene -> user selects pause -> user clicks quit -> [ad loads] -> Menu Scene
Both scenarios work perfectly for iOS 13
However, in iOS 12, only the user quitting mid game works, in the other scenario the app freezes (no obvious errors to me in the log)
Ending a game, via either method, calls the exact same function. Which uses a notification to load the ad.
The following code is all in the GameViewController. And the notification is posted in the GameScene.
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.showAd), name: NSNotification.Name(rawValue: "loadAndShow"), object: nil)
An ad is prepared in ViewDidLoad()
myAd = createAd()
And the function is called by the Notification
#objc func showAd() {
if (myAd.isReady) {
myAd.present(fromRootViewController: self)
myAd = createAd()
}
}
func createAd() -> GADInterstitial {
myAd = GADInterstitial(adUnitID: "MY ADMOB ID")
let request = GADRequest()
GADMobileAds.sharedInstance().requestConfiguration.testDeviceIdentifiers = ["MY DEVICE ID"]
myAd.delegate = self
myAd.load(request)
return myAd
}
Any help would be amazing
UPDATE
Have found a potential workaround.
Am now presenting the ad in a different thread and no longer experiencing any freezing.
DispatchQueue.main.async {
self.myAd.present(fromRootViewController: self)
}
Can only assume iOS13 has better handling for this. And the reason the "game quit" scenario worked was because it was transitioning to the menu scene which is also the GameViewController. The app didn't like presenting an ad from the GameViewController while also transitioning to a new scene.

BeginSheet doesn't show window

I have simple code :
var openPanel = NSOpenPanel();
openPanel.beginSheet(this.View.Window, (obj) => {
//do stuff
openPanel.endSheet(this.View.Window);
});
Sometime the sheet window is not shown and makes a sound like the window is busy. Is there anything wrong in my code?
I call this code from one item of splitViewcontroller.
I just made this same error, and had trouble with it for quite some time. I was following along with the Apple guide:
Using the Open and Save Panels
The main issue is that the Apple docs show us using the Objective-C method:
[panel beginSheetModalForWindow:window completionHandler:^(NSInteger result){ }
I did an ad hoc translation into Swift, with help from Xcode autocomplete:
let openPanel = NSOpenPanel()
openPanel.beginSheet(window) { (modalResponse: NSApplication.ModalResponse) in
}
This does not work. When the code is run, the Window's title bar disappears + no panel is shown.
Use the correct Swift method instead, beginSheetModal:
openPanel.beginSheetModal(for: window) { (modalResponse: NSApplication.ModalResponse) in
}
Try this:
let panel = NSOpenPanel()
self.window?.beginSheet(panel, completionHandler: { (modalResponse: NSModalResponse) in
if modalResponse == NSModalResponseOK {
// do your stuff
}
})

NSProgressIndicator on Modal Sheet Doesn't Animate

My main window controller has a toolbar item that triggers the presentation of a modal sheet. The sheet is supposed to display the progress of a lengthy, asynchronous process (e.g., sync local data with a server).
However, I can not get the (indeterminate) progress indicator to animate.
This is the action that triggers the modal sheet:
var syncProgressWindowController: SyncProgressWindowController!
// ...
#IBAction func syncWithServer(_ sender: AnyObject) {
// (Actual HTTP code not implemented)
syncProgressWindowController = SyncProgressWindowController()
syncProgressWindowController.loadWindow()
guard let modalWindow = syncProgressWindowController.window else {
return
}
self.window?.beginSheet(modalWindow, completionHandler: { (response) in
// THIS GETS EXECUTED.
// However, the code below has no effect:
self.syncProgressWindowController.progressIndicator.startAnimation(self)
// self.syncProgressWindowController.progressIndicator is
// NOT nil, despite windowDidLoad() not being called
// (see below)
})
}
The modal sheet window controller (class SyncProgressWindowController above) is defined like this:
#IBOutlet weak var progressIndicator: NSProgressIndicator!
convenience init() {
self.init(windowNibName: "SyncProgressWindow")
}
override func windowDidLoad() {
super.windowDidLoad()
// Breakpoints here don't work, logs don't print to the console.
// Not called? But outlet _is_ set (see above).
}
The xib file (SyncProgressWindow.xib) has:
File's Owner Identity/Class set to "SyncProgressWindowController"
Window has New Referencing Outlet to File's Owner's window
Window has delegate outlet wired to "File's Owner" (just in case - but delegate methods don't seem to get called either).
Window has "Visible at Launch" unchecked (and is therefore displayed modally with no problems).
Progress has New Referencing Outlet wired to File's Owner's progressIndicator.
However:
SyncProgressWindowController's windowDidLoad() does not get called (Execution does not stop at breakpoints there and logs aren't printed).
Despite that, the property/outlet progressIndicator is set somehow, because the app does not crash when I attempt to animate it, with code like this:
self.syncProgressWindowController.progressIndicator.startAnimation(self)
What am I missing?
completionHandler will be fired when you close sheet by endSheet(_:returnCode:) So you start indicator before sheet will be closed.
I'm not good in xib files, but when i disabled row with loadWindow, windowDidLoad was called. I'm not sure it's right way.

Swift 2 Is it possible to add a web link to an annotation callout?

I'm able to create pin's with their popup's as well as the info-light button to the right. And when tapped, the info button pops up an alert with some text and an "ok" button at the bottom. Is it now possible to add a link at the bottom of the text that will direct the user to a URL, saw wikkipedia for example in safari?
I've used the following called function to succesfully do so with a regular button in the mapview, but I can't figure out how to implement it the way I've stated above
#IBAction func webLink(sender: AnyObject) {
if let url = NSURL(string: "http://www.wikipedia.com") {
UIApplication.sharedApplication().openURL(url)
}
}

Swift NSWindow shows up and disappears immediately

I'm a complete beginner to Swift, so this may be a silly question, but I can't figure out how this works...
I have a view with a button inside which calls the following code:
let window = NSWindow()
window.center()
window.title = "test"
window.makeKeyAndOrderFront(self)
When I click the button the window opens just for a moment and disappears a few milliseconds later.
Can anyone help me with that? It seems I have a quite serious misunderstanding about views in Cocoa ;-)
Thanks
Tom
The problem is that you are creating and 'storing' the NSWindow in your button action function. That means that as soon as that button action is done, the NSWindow will go out of context, and be released and thus disappear.
This is how the memory management in Swift works: as soon as nobody owns an object anymore, it will be released.
What you should do is put your window in an instance variable. Like for example:
class YourViewController: NSViewController {
private var window: NSWindow!
#IBAction func buttonAction(sender: UIButton) {
window = NSWindow()
window.center()
window.title = "test"
window.makeKeyAndOrderFront(self)
}
}
The hint about makeKeyAndOrderFront(nil) makes no difference. Passing either nil or self is fine. But latter, how you did it originaly, makes more sense.

Resources