Loading XIB Not Working ( Mac ) - objective-c

So my current code (used from another question) looks like this:
NSWindowController * wc=[[NSWindowController alloc] initWithWindowNibName:#"POP"];
[wc showWindow:self];
The .xib is name POP.xib (Push or Pull).
Please help I would love simple alternatives.

Ok there are some things that you should fix:
On your POP.xib you must set your File's Owner class to NSWindowController. Then you should connect its window property to the window you want to show (the window in the xib).
What I found was that because you're using ARC the window shows up for a split second and then disappears. This happens because there is nothing to retain your window controller and the ARC obviously sends a release message to it just after instantiation. So make sure that you are retaining it as well (I just added a strong property and set it to the NSWindowController we instantiate in the first line and worked fine).
Here is a corrected project

Related

Reasons for an IBOutlet to be nil

What are the reasons why an IBOutlet (connected) could be nil?
I have one in may application which is always nil, even if I recreate everything from scratch (declaration and control).
It could be that your nib is messed up, but I find a common reason is having two instances where you think you only have one, and the one you're using in your code is not the one you connected.
If you've also defined a loadView method that creates the view, it is possible based on how you initialize it. If you initialize it using alloc-init and the nib name is not the same as class name, then you can have a case where the outlet is nil. But Chuck's answer seems more reasonable to assume.
One reason I just got stung by: If the nib file is not included in the target resource files for some reason (like you had the targets unchecked when you added it to the project), Xcode doesn't throw an error but all the outlets from that nib are going to be null...
One possibility:
Suppose the IBOutlet container is a singleton object with a function like:
+ (singletonObject*) sharedInstance {
if(!gGlobalSingletonPointer) {
gGlobalSingletonPointer = [[singletonObject alloc] init];
}
return gGlobalSingletonPointer;
}
You create the singleton object "on demand" if it doesn't already exist.
You save a global pointer to it, as you create it, in that function.
If you also instantiate such an object in InterfaceBuilder, and connect its outlets, this object will be created without sharedInstance being called. If you subsequently call sharedInstance, a new object is created (sans IBOutlet connections).
The solution is to update the global pointer in singletonObject's init or awakeFromNib function.
Are you using a UINavigationController?
If so, open your MainWindow.xib in IB and make sure that your root controller's nib name is set correctly in the Attributes Inspector.
Why would this not be set correctly? One reason is the 'rename' refactoring doesn't update this, and then the internals won't find the nib with which to wire your UI. Or you renamed the nib yourself, and didn't update this field.
Are you doing something unusual with File's Owner? If you're not in one of the situations where the nib is loaded automatically (main nib loaded by application or nib loaded by view controller, document, or window controller), then you have to load the nib programmatically.

Showing an NSPanel on demand - NSPanel not showing?

Hey guys,
I thought this would be an incredibly simple thing to do, but it's proving trickier than I thought.
I want to be able to show an NSPanel that displays a circular progress bar and the name of the thing that's being processed.
So, I made an NSPanel containing those controls in IB, then I created a subclass of NSWindowController. Created outlets for the controls and linked those up.
However, when I try using this code to display the NSPanel, nothing happens:
[[[self controller] msgSubject] setValue:[msg subject]];
[[[self controller] window] setLevel:NSFloatingWindowLevel];
[[self controller] showWindow:self];
[[[self controller] window] makeKeyAndOrderFront:self];
[self controller] is a method that lazily instantiates the NSWindowController subclass. I tried adding the call to makeKeyAndOrderFront: in vain, but the panel still isn't popping up.
I tried debugging and what I found is that when -initWithWindow: is called, the NSWindow that's passed in as an argument has all zeroed out instance variables, leading me to believe there's some sort of IB linking issue going on here.
Any ideas? I'm guessing I missed something really obvious, but I can't for the life of me figure out what it is.
Please post the contents of the [self controller] method so we can begin to see exactly how you're creating and using the NSWindowController subclass. Are you creating it using the initWithWindow: method directly, or is that method (which is the designated initializer) being called indirectly from one of the other init methods? If you are calling it directly, that doesn't really make sense to me as you said you already created the window in nib file itself. If on the other hand, it's being called indirectly by -initWithWindowNibName:, then it would help to see that code.
NSWindowController's are primarily used/set up in 2 different ways. One way is to create an NSWindow programmatically, and then create the NSWindowController subclass and feed that window in as the window the controller will manage. The second, and more frequently used method, is to create a nib file that houses the window, which is what it sounds like you're trying to do. In this method, you generally use the -initWithWindowNibName: initializer. As long as you pass in the proper nib name (generally without the ".nib" part of the filename), and that nib file can be properly found at runtime, and the file's owner in this nib file is set to be the custom NSWindowController subclass, and the window outlet of this subclass is properly hooked up to your window, then you should be all set.
Might want to double-check to make sure that the nib file you want to load is actually in the app bundle. (I've occasionally forgotten to add it to the target so at runtime the nib file couldn't be located and so the -initWithWindow: method would always show a nil parameter).

Possible to check if nib is already loaded?

In a loop i am using the following code to load the preferences window if the user has not entered his/her settings.
[NSBundle loadNibNamed:#"prefs" owner:self];
My problem is that everytime the loop runs a new window opens again and again until, is there any way to check if the window or nib is already loaded once?
Thanks! :)
Rather than micro-managing the nib loading as you are doing, just use a subclass of NSWindowController to handle the preferences window. NSWindowController handles all the nib management for you, you just need to call -showWindow: to display the window. The only real trick with NSWindowController is to make sure you hook up the window outlet of File's Owner in the nib itself.
To instantiate the class, use ‑initWithWindowNibName: passing in the name of the nib.
As Ief2 mentioned, you should configure this object to act as a singleton.
Maybe you can make a class named PreferencesController, make that class load the nib when requested, save the the window in an ivar. Every time you create an instance of the class and activate it, check if the window ivar is nil. If it is, load the nib, otherwise just make the window key and order front.
In addition to storing the window, you could also monitor it for when the user closes it. When he or she does, you can release your ivar and ser it to nil. Now when you request it again, you'll see you have no window cached and you'll have to reload the nib. It saves memory though.
It also may be advised to make a shared instance of the class. I cannot include a sample because I'm on my iPod touch, but a quick Google search should be really helpful.
Hope it helps,
ief2
EDIT: The link below holds an example about singletons:
http://eschatologist.net/blog/?p=178

Using NSProgressIndicator inside an NSMenuItem

I'm trying to use a NSProgressIndicator (indeterminate) inside of a statusbar-menu. I'm using an NSView-object as view for the menuitem, and then subviews the progress indicator to display it. But whenever i try to call the startAnimation: for the progress, nothing happens. When i try do the very same thing on a normal NSWindow it works perfectly, just not when inside a menuitem.
I'm new to both cocoa and objective-c so I might've overlooked something "obvious" but I've searched quite a bit for a workaround but without success. I found something about menuitems cant be updated while shown and that you need to use a bordeless window instead. But I have not been able to confirm this in any documentation.
Edit:
Ok, almost works now. When using the setUsesThreadedAnimation: and from a MenuDelegate's menuWillOpen and creating a new thread. This thread runs a local method:
-(void) doWork(NSProgressIndicator*) p{
[p startAnimation:self];
}
This will start the progressindicator on a random(?) basis when opening the menu. If I call startAnimation: directly without going through doWork: (still using a new thread), it never works. Doesn't setUsesThreadedAnimation: make the progress-bar create it's own thread for the animation?
Solved it by using:
[progressIndicator performSelector:#selector(startAnimation:)
withObject:self
afterDelay:0.0
inModes:[NSArray
arrayWithObject:NSEventTrackingRunLoopMode]];
Inside the menuWillOpen:, the problem seems to have been calling startAnimation: before the progressbar was finished drawing itself.
How are you referencing the NSProgressIndicator that is in the view (and the one in the window, for that matter)? For example, do you have a controller class that has IBOutlet's hooked up to the progress indicators? If you are using an IBOutlet, are you sure it's hooked up properly in the nib file?
Also, where and when are you calling startAnimation:? (We need to see some code).
One thing that can sometimes happen is that you forget to hook up an IBOutlet in the nib. Then, when you attempt to tell the object to do something in code at runtime, the IBOutlet is nil, and so what you think is a message being sent to your object is in fact, a message being sent to nil. In other words, it's just ignored, and effectively looks like it's not working.
Provided you do have a (potentially) valid reference to the UI object, the other common issue you'll see is when a developer is trying to send a message to the object at "too early" of a time. In general, init methods are too early in the controller object's lifetime to be able to send messages to user interface objects—those IBOutlet's are still nil. By the time -awakeFromNib is called, IBOutlet's should be valid (provided you hooked them up in IB) and you can then send the message to the UI object.
Have you told it to use threaded animation via -setUsesThreadedAnimation:?

How does NSViewController avoid bindings memory leak? [have sample app]

I'm trying to implement my own version of NSViewController (for backwards compatibility), and I've hit a problem with bindings: Since bindings retain their target, I have a retain circle whenever I bind through File's owner.
So I thought I'd just explicitly remove my view from its superview and release the top level objects, and that would take care of the bindings, because my controller isn't holding on to the views anymore, so they release me and I can go away. But for some reason, my view controller still doesn't get released. Here's a sample app exhibiting the problem:
http://dl.dropbox.com/u/34351/BindingsLeak.zip
Build it, launch it, and hit Cmd-K ("Create Nib" in "Edit" menu) to load a NIB into the empty window. Hit Cmd-K again to release the first view controller (TestNibOwner) and load a new one. The old view controller never gets dealloced, though.
Remove the "value" binding on the checkbox, and it gets released just fine.
If you set breakpoints at the release/retain/autorelease overrides, you see that _NSBindingInfo retains the TestNibOwner, but never releases it in the leaking case.
Anyone know how to fix this?
Doing a little investigation with class-dump and friends, it looks like Apple has a private class called NSAutounbinder that takes care of this dirty work for classes such as NSViewController and NSWindowController. Can't really tell how it works or how to replicate it though.
So, I can't really answer your question on how to prevent the retain cycle from happening for arbitrary bindings in a loaded nib, but perhaps it's some consolation to know that Apple is cheating, and you're not missing anything obvious. :-)
One thing I've done for the same problem is to create a proxy NSObjectController inside my nib. My NSViewController-like class has a pointer to this proxy and all bindings are bound through it. When I want to cleanup the view controller, I then do [selfProxy setContent:nil] on the object controller and release the view controller. In this instance the NSObjectController proxy acts as the auto-unbinder in this case.
It's more manual and you can't just release the view by itself, but it does solve the retain problem.
I'd suggest you do this:
-(void) releaseTopLevelObjects
{
// Unbind the object controller's content by setting it to nil.
[selfProxy setContent:nil];
NSLog( #"topLevelObjects = %#", topLevelObjects );
[topLevelObjects release];
topLevelObjects = nil;
}
In your nib, bindings would happen through a path like:
selfProxy.content.representedObject.fooValue
When you remove your view from its superview, are you also sending it another -release message? It was created by unarchiving from the nib, right?