I am building an application in AppleScriptObjC and I have a beginner question - how can I handle clicking on tab buttons in my app? I'm trying to make it have different sizes for each tab. I can make the window resize, but not when you click on a tab. Anyway, I've connected the tab view to the delegate
and such, and added a didSelectTabView function as follows:
on didSelectTabViewItem_(tabItem)
display alert "Testing"
end didSelectTabViewItem_
...and I get the following error:
2013-05-30 18:50:10.970 MacUtil[16354:303] Error setting value for key path self of object <AppDelegate #0x1005d3040: OSAID(4)> (from bound object <NSTabView: 0x101c05490>): [<AppDelegate 0x1005d3040> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key self.
2013-05-30 18:50:10.972 MacUtil[16354:303] (
0 CoreFoundation 0x00007fff911210a6 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff9522e3f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff91120ee8 +[NSException raise:format:arguments:] + 104
3 AppKit 0x00007fff92e3414c -[NSBinder _setValue:forKeyPath:ofObject:mode:validateImmediately:raisesForNotApplicableKeys:error:] + 902
4 AppKit 0x00007fff92e33d6d -[NSBinder setValue:forBinding:error:] + 248
5 AppKit 0x00007fff93493625 -[NSViewStateBinder _setValue:forBinding:errorFallbackMessage:] + 63
6 AppKit 0x00007fff933a5198 -[NSTabViewBinder tabView:didSelectTabViewItem:] + 330
7 AppKit 0x00007fff934b9c75 -[_NSBindingAdaptor tabView:didSelectTabViewItem:] + 136
8 AppKit 0x00007fff92fe9029 -[NSTabView selectTabViewItem:] + 1172
9 AppKit 0x00007fff9303ea8c -[NSTabView mouseDown:] + 156
10 AppKit 0x00007fff92fad60e -[NSWindow sendEvent:] + 6853
11 AppKit 0x00007fff92fa9744 -[NSApplication sendEvent:] + 5761
12 AppKit 0x00007fff92ebf2fa -[NSApplication run] + 636
13 AppKit 0x00007fff92e63cb6 NSApplicationMain + 869
14 MacUtil 0x0000000100000f0a main + 74
15 libdyld.dylib 0x00007fff93a297e1 start + 0
16 ??? 0x0000000000000003 0x0 + 3
)
Any help would be appreciated!
Solved! I just had to uncheck "Raises for Non Applicable Keys" in the place where you bind it to the app delegate. It was doing that because I hadn't implemented all of the methods for tab view event handling.
Related
I'm getting an error that I can't decipher when I try to add a tableview to a new tabbed project.
If I add the tableview to my storyboard, then build the app - it's fine. However as soon as I ctrl+drag the "delegate" and "dataSource" to that yellow circle with a square box icon to link it to my controller, the build fails. Why does this happen?
Exact repro steps:
Create a new "Tabbed View" project in Xcode.
In storyboard, I drag a "Table View" onto the top storyboard.
I "ctrl click" on the "Table View", then drag "dataSource" and "delegate" to the yellow circle + white box icon at the top of the storyboard.
I open FirstViewController.swift and I try to add UITableViewDelegate, UITableViewDataSource to the class. However neither of these show up in autocomplete as if the controller doesn't think they exist. If I command click on one, I get "symbol not found".
FirstViewController.swift
//
// FirstViewController.swift
// To Do List
//
// Created by Donald Pinkus on 12/14/14.
// Copyright (c) 2014 Don Pinkus. All rights reserved.
//
import UIKit
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Build error
2014-12-14 00:27:04.278 To Do List[11149:566768] -[To_Do_List.FirstViewController tableView:numberOfRowsInSection:]: unrecognized selector sent to instance 0x7faafae29ba0
2014-12-14 00:27:04.285 To Do List[11149:566768] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[To_Do_List.FirstViewController tableView:numberOfRowsInSection:]: unrecognized selector sent to instance 0x7faafae29ba0'
*** First throw call stack:
(
0 CoreFoundation 0x0000000105422f35 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000106f66bb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010542a04d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x000000010538227c ___forwarding___ + 988
4 CoreFoundation 0x0000000105381e18 _CF_forwarding_prep_0 + 120
5 UIKit 0x0000000105f26212 -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 2353
6 UIKit 0x0000000105f2a098 -[UITableViewRowData numberOfRows] + 97
7 UIKit 0x0000000105d928fc -[UITableView noteNumberOfRowsChanged] + 133
8 UIKit 0x0000000105d9203d -[UITableView reloadData] + 1316
9 UIKit 0x0000000105d9ad86 -[UITableView layoutSubviews] + 31
10 UIKit 0x0000000105d27973 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 521
11 QuartzCore 0x0000000109c25de8 -[CALayer layoutSublayers] + 150
12 QuartzCore 0x0000000109c1aa0e _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
13 UIKit 0x0000000105d1b847 -[UIView(Hierarchy) layoutBelowIfNeeded] + 611
14 UIKit 0x0000000105e0ff06 -[UITabBarController _layoutViewController:] + 500
15 UIKit 0x0000000105e10014 -[UITabBarController _wrapperViewForViewController:] + 252
16 UIKit 0x0000000105e16e92 -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 378
17 UIKit 0x0000000105e13069 -[UITabBarController _setSelectedViewController:] + 311
18 UIKit 0x0000000105d1f5ce +[UIView(Animation) performWithoutAnimation:] + 65
19 UIKit 0x0000000105e10106 -[UITabBarController _selectDefaultViewControllerIfNecessaryWithAppearanceTransitions:] + 221
20 UIKit 0x0000000105e10dfe -[UITabBarController viewWillAppear:] + 121
21 UIKit 0x0000000105dd7821 -[UIViewController _setViewAppearState:isAnimating:] + 487
22 UIKit 0x0000000105d1a136 -[UIView(Hierarchy) _willMoveToWindow:withAncestorView:] + 564
23 UIKit 0x0000000105d24aaa -[UIView(Internal) _addSubview:positioned:relativeTo:] + 419
24 UIKit 0x0000000105cf2e37 -[UIWindow addRootViewControllerViewIfPossible] + 456
25 UIKit 0x0000000105cf3041 -[UIWindow _setHidden:forced:] + 247
26 UIKit 0x0000000105cff72c -[UIWindow makeKeyAndVisible] + 42
27 UIKit 0x0000000105caa061 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2628
28 UIKit 0x0000000105cacd2c -[UIApplication _runWithMainScene:transitionContext:completion:] + 1350
29 UIKit 0x0000000105cabbf2 -[UIApplication workspaceDidEndTransaction:] + 179
30 FrontBoardServices 0x0000000108af32a3 __31-[FBSSerialQueue performAsync:]_block_invoke + 16
31 CoreFoundation 0x000000010535853c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
32 CoreFoundation 0x000000010534e285 __CFRunLoopDoBlocks + 341
33 CoreFoundation 0x000000010534e045 __CFRunLoopRun + 2389
34 CoreFoundation 0x000000010534d486 CFRunLoopRunSpecific + 470
35 UIKit 0x0000000105cab669 -[UIApplication _run] + 413
36 UIKit 0x0000000105cae420 UIApplicationMain + 1282
37 To Do List 0x00000001052403ce top_level_code + 78
38 To Do List 0x000000010524040a main + 42
39 libdyld.dylib 0x0000000107740145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
You are missing the numberOfRowsInSection method which is required.
In order to be a UITableViewDataSource you are required to implement numberOfRowsInSection and cellForRowAtIndexPath
I have a master-detail kind of application OS X 10.9 only:
An NSTableView on the left side of the window, the details as NSTextFields on the right side.
I have not set the tab order specifically, out of the box works just fine.
Except after inserting a new object:
after inserting a new object the object is selected in the NSTableView.
hit tab
the first NSTextField is selected
write something, hit tab
now instead of selecting the next NSTextField nothing is selected,
hit tab
the NSTableView is selected
hit tab
the first NSTextField is selected
What i want:
after inserting a new object, the first NSTextField of the detail part should be selected
hit tab
the next NSTextField of the detail part should be selected
…
UPDATE:
I found that the strange behaviour is triggered by enabling NSArrayController’s "Auto Rearrange Content“ in Interface Builder. If i disable it, i do not loose my focus anymore. See CoreData-bound NSTableView loses input focus when items change, but only if sorted.
BUT, of course, i still want my content to be automatically sortet — just without loosing my focus during that operation. Can this be done?
UPDATE2: i followed #KenThomases advice and recorded the stack trace at the moment, when my textfield looses keyboard focus:
2014-08-17 16:30:26.003 ResponderExperiment[712:303] (
0 ResponderExperiment 0x00000001000014dd -[WMWindow makeFirstResponder:] + 61
1 AppKit 0x00007fff8d25c778 -[NSTextView(NSPrivate) _giveUpFirstResponder:] + 257
2 AppKit 0x00007fff8d25c56c -[NSTextView(NSKeyBindingCommands) insertTab:] + 270
3 AppKit 0x00007fff8d22dc2f -[NSResponder doCommandBySelector:] + 71
4 AppKit 0x00007fff8d25b10a -[NSTextView doCommandBySelector:] + 196
5 AppKit 0x00007fff8d22d151 -[NSKeyBindingManager(NSKeyBindingManager_MultiClients) interpretEventAsCommand:forClient:] + 1392
6 AppKit 0x00007fff8d24c1c2 -[NSTextInputContext handleEvent:] + 845
7 AppKit 0x00007fff8d22b9dd -[NSView interpretKeyEvents:] + 180
8 AppKit 0x00007fff8d24bd6d -[NSTextView keyDown:] + 658
9 AppKit 0x00007fff8d1f856b -[NSWindow sendEvent:] + 1843
10 AppKit 0x00007fff8d199b32 -[NSApplication sendEvent:] + 3395
11 AppKit 0x00007fff8cfe99f9 -[NSApplication run] + 646
12 AppKit 0x00007fff8cfd4783 NSApplicationMain + 940
13 ResponderExperiment 0x0000000100002de2 main + 34
14 libdyld.dylib 0x00007fff8c5bf5fd start + 1
15 ??? 0x0000000000000003 0x0 + 3
)
2014-08-17 16:30:26.014 ResponderExperiment[712:303] (
0 ResponderExperiment 0x00000001000014dd -[WMWindow makeFirstResponder:] + 61
1 AppKit 0x00007fff8d03c918 -[NSControl abortEditing] + 83
2 AppKit 0x00007fff8d2723e0 -[NSValueBinder discardEditing] + 162
3 AppKit 0x00007fff8d1aee30 -[NSController discardEditing] + 115
4 AppKit 0x00007fff8d1af971 -[NSArrayController rearrangeObjects] + 27
5 AppKit 0x00007fff8d3697a9 -[NSArrayController observeValueForKeyPath:ofObject:change:context:] + 294
6 AppKit 0x00007fff8d39ac08 -[NSArrayController _setMultipleValue:forKeyPath:atIndex:] + 323
7 AppKit 0x00007fff8d39ba12 -[NSArrayController _setSingleValue:forKeyPath:] + 137
8 Foundation 0x00007fff8bf9e19a -[NSObject(NSKeyValueCoding) setValue:forKeyPath:] + 285
9 AppKit 0x00007fff8d25444c -[NSBinder _setValue:forKeyPath:ofObject:mode:validateImmediately:raisesForNotApplicableKeys:error:] + 364
10 AppKit 0x00007fff8d254287 -[NSBinder setValue:forBinding:error:] + 245
11 AppKit 0x00007fff8d74c4ee -[NSValueBinder _applyObjectValue:forBinding:canRecoverFromErrors:handleErrors:typeOfAlert:discardEditingCallback:otherCallback:callbackContextInfo:didRunAlert:] + 194
12 AppKit 0x00007fff8d74c871 -[NSValueBinder applyDisplayedValueHandleErrors:typeOfAlert:canRecoverFromErrors:discardEditingCallback:otherCallback:callbackContextInfo:didRunAlert:error:] + 621
13 AppKit 0x00007fff8d74c9d4 -[NSValueBinder _applyDisplayedValueIfHasUncommittedChangesWithHandleErrors:typeOfAlert:discardEditingCallback:otherCallback:callbackContextInfo:didRunAlert:error:] + 127
14 AppKit 0x00007fff8d253c2e -[NSValueBinder validateAndCommitValueInEditor:editingIsEnding:errorUserInterfaceHandled:] + 436
15 AppKit 0x00007fff8d253a57 -[_NSBindingAdaptor _validateAndCommitValueInEditor:editingIsEnding:errorUserInterfaceHandled:bindingAdaptor:] + 160
16 AppKit 0x00007fff8d25399d -[_NSBindingAdaptor validateAndCommitValueInEditor:editingIsEnding:errorUserInterfaceHandled:] + 260
17 AppKit 0x00007fff8d25e0ba -[NSTextField textShouldEndEditing:] + 402
18 AppKit 0x00007fff8d25dc63 -[NSTextView(NSSharing) resignFirstResponder] + 393
19 AppKit 0x00007fff8d136170 -[NSWindow makeFirstResponder:] + 455
20 ResponderExperiment 0x000000010000154c -[WMWindow makeFirstResponder:] + 172
21 AppKit 0x00007fff8d25c778 -[NSTextView(NSPrivate) _giveUpFirstResponder:] + 257
22 AppKit 0x00007fff8d25c56c -[NSTextView(NSKeyBindingCommands) insertTab:] + 270
23 AppKit 0x00007fff8d22dc2f -[NSResponder doCommandBySelector:] + 71
24 AppKit 0x00007fff8d25b10a -[NSTextView doCommandBySelector:] + 196
25 AppKit 0x00007fff8d22d151 -[NSKeyBindingManager(NSKeyBindingManager_MultiClients) interpretEventAsCommand:forClient:] + 1392
26 AppKit 0x00007fff8d24c1c2 -[NSTextInputContext handleEvent:] + 845
27 AppKit 0x00007fff8d22b9dd -[NSView interpretKeyEvents:] + 180
28 AppKit 0x00007fff8d24bd6d -[NSTextView keyDown:] + 658
29 AppKit 0x00007fff8d1f856b -[NSWindow sendEvent:] + 1843
30 AppKit 0x00007fff8d199b32 -[NSApplication sendEvent:] + 3395
31 AppKit 0x00007fff8cfe99f9 -[NSApplication run] + 646
32 AppKit 0x00007fff8cfd4783 NSApplicationMain + 940
33 ResponderExperiment 0x0000000100002de2 main + 34
34 libdyld.dylib 0x00007fff8c5bf5fd start + 1
35 ??? 0x0000000000000003 0x0 + 3
)
So perhaps I could write my own NSArrayController rearrangeObjects: method, that does not loose focus?
Here's a possible solution. The idea is to re-implement the response of the text field (or, more accurately, the field editor serving the text field) to the Tab key as two separate steps. First, end editing, which will make the array controller rearrange its content. We end editing by resetting focus, so we don't care what the array controller may happen to do to focus anyway. Then, advance the focus from the originally-focused text field ourselves.
Set a delegate on your text fields. In that delegate, implement the following method:
- (BOOL) control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)command
{
if (command == #selector(insertTab:))
{
// End editing. This will commit the edited value and cause the array controller
// to rearranged its contents.
[control.window makeFirstResponder:nil];
// This will put focus on the next control from the text field.
[control.window selectKeyViewFollowingView:control];
// Prevent the normal processing of this command
return YES;
}
if (command == #selector(insertBacktab:))
{
// End editing. This will commit the edited value and cause the array controller
// to rearranged its contents.
[control.window makeFirstResponder:nil];
// This will put focus on the previous control from the text field.
[control.window selectKeyViewPrecedingView:control];
// Prevent the normal processing of this command
return YES;
}
return NO;
}
One thing I'm not sure of: what happens if instead of Tab-ing away from the text field, you click on another text field. Does the array controller still reset focus in that case?
In my case, I have overrided abortEditing method of NSControl, with my own logic.
- (BOOL)abortEditing {
MyObject *object = [myArrayController.arrangedObjects objectAtIndex:self.editedRow];
return ![[Manager sharedInstance] isObjectBeingEditing:object];
}
I am using this project, created by aneesh171 that shows the creation of checkboxes inside NSTableView and how to bind them. I am new to OSX development and trying to understand how it works.
The project is basically checkboxes inside a NSTableView's column that is bound to an array controller.
For some reason, when I deselect one of those checkboxes, the following messages appear on the console window:
2014-04-03 04:22:55.579 MyApp[5735:303] Error setting value for key path objectValue.selected of object <NSAutounbinder: 0x600000258120 - a nonretaining proxy for <NSTableCellView: 0x60000019f890>> (from bound object <NSButton: 0x60000015efb0>): [<__NSDictionaryI 0x61000006f540> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key selected.
2014-04-03 04:22:55.581 MyApp[5735:303] (
0 CoreFoundation 0x00007fff87b3a25c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff8a3f6e75 objc_exception_throw + 43
2 CoreFoundation 0x00007fff87b3a038 +[NSException raise:format:arguments:] + 104
3 AppKit 0x00007fff927936c5 -[NSBinder _setValue:forKeyPath:ofObject:mode:validateImmediately:raisesForNotApplicableKeys:error:] + 837
4 AppKit 0x00007fff92793327 -[NSBinder setValue:forBinding:error:] + 245
5 AppKit 0x00007fff92c8b4ee -[NSValueBinder _applyObjectValue:forBinding:canRecoverFromErrors:handleErrors:typeOfAlert:discardEditingCallback:otherCallback:callbackContextInfo:didRunAlert:] + 194
6 AppKit 0x00007fff92c8b871 -[NSValueBinder applyDisplayedValueHandleErrors:typeOfAlert:canRecoverFromErrors:discardEditingCallback:otherCallback:callbackContextInfo:didRunAlert:error:] + 621
7 AppKit 0x00007fff927c5107 -[NSValueBinder performAction:] + 288
8 AppKit 0x00007fff927c4fc5 -[_NSBindingAdaptor _objectDidTriggerAction:bindingAdaptor:] + 133
9 AppKit 0x00007fff927531a0 -[NSControl sendAction:to:] + 56
10 AppKit 0x00007fff9279fced -[NSCell _sendActionFrom:] + 128
11 AppKit 0x00007fff927b96c5 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 2316
12 AppKit 0x00007fff927b8a97 -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 487
13 AppKit 0x00007fff927b81ad -[NSControl mouseDown:] + 706
14 AppKit 0x00007fff92739b48 -[NSWindow sendEvent:] + 11296
15 AppKit 0x00007fff926d86e4 -[NSApplication sendEvent:] + 2021
16 AppKit 0x00007fff92528b89 -[NSApplication run] + 646
17 AppKit 0x00007fff92513913 NSApplicationMain + 940
18 MyApp 0x0000000100049132 main + 34
19 libdyld.dylib 0x00007fff85ffe5fd start + 1
When the checkbox is selected this message does not show on the console.
Can you guys tell me what is wrong?
I updated the git version of the project.
Whenever you bind a control through value binding, then it calls its getter method to load the values. whereas when you tries to modify these values, it will try to call the setter method of the property. In the project the dictionaries were hardcoded therefore there were no setter method and that is the reason why you got the "Error setting value for key path objectValue.selected".
Check the new version where the FruitModel has been created which resolves the setter issue.
Let me know if you face any problems.
I have a simple NSArrayController hooked up to one of my coreData models. I can easily show all the items in a NSTableView without problem, however, if I try to bind a NSTableColumn containing a NSPopUpButtonCell to the arrangedObjects on the same controller, I get a nasty exception thrown at me. (If I bind to a NSPopupButton that is outside the table, however, everything seems to work correctly)
Catchpoint 2 (throw)2011-12-18 16:00:07.251 MyApp[6050:707] -[MyCoreDataModel count]: unrecognized selector sent to instance 0x10045aea0
Catchpoint 2 (exception thrown).2011-12-18 16:01:32.901 MyApp[6050:707] -[MyCoreDataModel count]: unrecognized selector sent to instance 0x10045aea0
2011-12-18 16:01:32.907 MyApp[6050:707] (
0 CoreFoundation 0x00007fff9191e286 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff93bd6d5e objc_exception_throw + 43
2 CoreFoundation 0x00007fff919aa4ce -[NSObject doesNotRecognizeSelector:] + 190
3 CoreFoundation 0x00007fff9190b133 ___forwarding___ + 371
4 CoreFoundation 0x00007fff9190af48 _CF_forwarding_prep_0 + 232
5 AppKit 0x00007fff8b5bbad3 -[_NSSelectionBinderPlugin populateObject:withContent:valueKey:objectKey:insertsNullPlaceholder:] + 235
6 AppKit 0x00007fff8b45242e -[NSSelectionBinder _adjustObject:mode:observedController:observedKeyPath:context:editableState:adjustState:] + 678
7 AppKit 0x00007fff8b56f11a -[NSValueBinder updateTableColumnDataCell:forDisplayAtIndex:] + 145
8 AppKit 0x00007fff8b5af502 -[_NSBindingAdaptor tableColumn:willDisplayCell:row:] + 112
9 AppKit 0x00007fff8b0a00b1 -[NSTableView _tryCellBasedMouseDown:atRow:column:withView:] + 498
10 AppKit 0x00007fff8b062a4c -[NSTableView mouseDown:] + 1072
11 AppKit 0x00007fff8afc90e0 -[NSWindow sendEvent:] + 6306
12 AppKit 0x00007fff8af6168f -[NSApplication sendEvent:] + 5593
13 AppKit 0x00007fff8aef7682 -[NSApplication run] + 555
14 AppKit 0x00007fff8b17680c NSApplicationMain + 867
15 InstaLibrary 0x0000000100001732 main + 34
16 InstaLibrary 0x0000000100001704 start + 52
Why is this the case? How come you can't reuse the array controller in multiple places?
How come you can't reuse the array controller in multiple places?
That's not what the error message says. What the error message says is that you tried to bind an array property to a property whose value is not an array:
2011-12-18 16:01:32.901 MyApp[6050:707] -[MyCoreDataModel count]: unrecognized selector sent to instance 0x10045aea0
Meaning “I tried to treat this as an array (send it count), but it wasn't an array (and so didn't respond to count), and that's a problem”.
You've already identified the problem binding, so now you simply need to fix it. For more specific advice, you'll need to edit your question to include at least one screenshot of the binding in question, showing what object is it on, which binding is it, what object did you bind to, what controller key did you set, and what model key path did you set.
I'm working on a application for OS X where I use a custom window that draws an image as the background, including the title bar. I've been modifying this code to draw the window, and then calling [NSWindow standardWindowButton:forStyleMask:] to get the standard close, minimize, and maximize buttons.
The problem is my application uses NSPopovers, and when I close or minimize the application while a popover is open, it will close the popover or show an animation of the popover minimizing instead of closing the application. Is there a way to override the default close/minimize behavior in an NSWindow so I can dismiss any open popovers first?
Thanks, and sorry if this is an obvious question — this is my first time working with the OS X SDK so I don't have a lot of experience.
EDIT: A few hours after I posted this I thought I had an obvious solution – use the NSWindowDelegate methods "windowWillClose:" and "windowWillMiniaturize:" and dismiss the popovers there. However, it seems that since the close/minimize buttons are closing the popover, that if a popover is open, these delegate methods won't be called. This takes me back to step 1, but hopefully knowing the behavior will help someone figure out the problem.
There's also another problem in with the NSPopovers and I don't know if it's connected or not, so I thought I would add it here just in case there was a common cause. Sometimes, when I attempt to dismiss a popover, I'll get this error (for context, I'm pressing an NSButton that calls a function that checks for the existence of the popover, and if it exists, closes it):
2011-08-30 11:24:08.949 Playground[11194:707] *** Assertion failure in +[NSView _findFirstKeyViewInDirection:forKeyLoopGroupingView:], /SourceCache/AppKit/AppKit-1138/AppKit.subproj/NSView.m:11026
2011-08-30 11:24:08.950 Playground[11194:707] this method is supposed to only be invoked on top level items
2011-08-30 11:24:08.958 Playground[11194:707] (
0 CoreFoundation 0x00007fff873d4986 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff87ac6d5e objc_exception_throw + 43
2 CoreFoundation 0x00007fff873d47ba +[NSException raise:format:arguments:] + 106
3 Foundation 0x00007fff8950314f -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 169
4 AppKit 0x00007fff88211064 +[NSView _findFirstKeyViewInDirection:forKeyLoopGroupingView:] + 137
5 AppKit 0x00007fff87d1f546 _replacementKeyViewAlongKeyViewPath + 565
6 AppKit 0x00007fff87d1f2ff -[NSView nextValidKeyView] + 179
7 AppKit 0x00007fff87d1f199 -[NSWindow _selectFirstKeyView] + 714
8 AppKit 0x00007fff882361cf _NSWindowRecursiveFindFirstResponder + 164
9 AppKit 0x00007fff882395c8 _NSWindowExchange + 79
10 AppKit 0x00007fff883a7e3a -[_NSWindowTransformAnimation startAnimation] + 426
11 AppKit 0x00007fff87c98bb2 -[NSWindow _doOrderWindow:relativeTo:findKey:forCounter:force:isModal:] + 592
12 AppKit 0x00007fff87c9890f -[NSWindow orderWindow:relativeTo:] + 154
13 AppKit 0x00007fff883dfaf0 _NSPopoverCloseAndAnimate + 948
14 Playground 0x00000001000078a4 -[MainWindowController dismissPopover:] + 100
15 Playgorund 0x0000000100007012 -[MainWindowController requestWasClicked:] + 98
16 CoreFoundation 0x00007fff873c411d -[NSObject performSelector:withObject:] + 61
17 AppKit 0x00007fff87ca2852 -[NSApplication sendAction:to:from:] + 139
18 AppKit 0x00007fff87ca2784 -[NSControl sendAction:to:] + 88
19 AppKit 0x00007fff87ca26af -[NSCell _sendActionFrom:] + 137
20 AppKit 0x00007fff87ca1b7a -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 2014
21 AppKit 0x00007fff87d2157c -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 489
22 AppKit 0x00007fff87ca0786 -[NSControl mouseDown:] + 786
23 AppKit 0x00007fff87c6b66e -[NSWindow sendEvent:] + 6280
24 AppKit 0x00007fff87c03f19 -[NSApplication sendEvent:] + 5665
25 AppKit 0x00007fff87b9a42b -[NSApplication run] + 548
26 AppKit 0x00007fff87e1852a NSApplicationMain + 867
27 Playground 0x0000000100001c52 main + 34
28 Playground 0x0000000100001c24 start + 52
29 ??? 0x0000000000000001 0x0 + 1
)
The solution turned out to be fairly simple.
When I created the button on the NSWindow, I changed the action and target of the button:
[closeButton setTarget:self.delegate]; // alternatively you can make it self.windowController
[closeButton setAction:#selector(closeThisWindow:)];
And then in the NSWindowController subclass, I implemented the method:
-(void)closeThisWindow {
[self close]; // for the minimize button you'll call [self.window miniaturize]
}
For some reason, the NSPopovers always reappear when the window is reopened or unminimized; since I actually want this behavior in my application, it's not a problem, but it's something to keep in mind if you use this solution. If you don't have any child windows, then you can just iterate through self.window.childWindows because NSPopovers are considered child windows. If you have other child windows you want to handle separately, you could add an array to the NSWindow subclass that monitors all of your popovers and just iterate through that.