On Dec 4, 2009, at 9:47 PM, DeNigris Sean wrote:

I'm trying to unit test a view class. As it is very thin (just delegates all work to the controller), all I want to check is that my connections (e.g. outlets and actions) are hooked up correctly.

I've been trying to:
1. Create an instance of my class
2. use NSBundle::loadNibFile: externalNameTable: withZone: to load the nib

You'd normally write this +[NSBundle loadNibFile:externalNameTable:withZone:] (or starting with '-' if you're referring to the instance method).

3. check the connections

The docs for loadNibFile (http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSBundle_AppKitAdditions/Reference/Reference.html ) seem to suggest that you can pass objects in: "A name table whose keys identify objects associated with your program or the nib file. The newly unarchived objects from the nib file use this table to connect to objects in your program."

You can really only pass in the NIB owner object. In the NIB, there's a proxy "virtual" object called File's Owner. Other objects in the NIB can target File's Owner for actions, bind to File's Owner, or connect their outlets to File's Owner. (It's actually more typical to connect outlets of the File's Owner to the other objects.)

When the NIB is loaded, the object you specify as the actual owner is plugged into the empty slot in the object graph represented by File's Owner, thereby connecting the newly-loaded object graph to your existing object graph.

The NIB also may have a proxy for the application object (NSApp), which is another way for the newly-loaded object graph to be connected to the existing object graph.


There are many methods for loading a NIB. The one you selected is perhaps the clumsiest. That said, the external name table provides a way to supply the NIB owner and receive the loaded top-level objects of the NIB. To supply the owner, the dictionary should have a key NSNibOwner mapping to the object to become the owner.


This code is in ruby, but it's just bridged to the corresponding Cocoa calls:
        view = MyView.new # subclass of NSWindowController

Which is it, a view or a window controller? Those are two radically different things, and you're confusing matters (and perhaps yourself) by naming a window controller a "view".

You normally wouldn't instantiate a view if you're going to be loading a chunk of GUI from a NIB. The NIB would have a "freeze-dried" view hierarchy and loading the NIB would instantiate it for you.

As Chris Hanson said, if you're really instantiating a window controller here, then you should let it load the NIB and establish itself as the owner.


        NSApplication.sharedApplication
        top_level = [] # I've tried passing everything I could think of here:
                                - view # the object instance
- "My View" => view # NSDictionary with key object name in IB and value object instance
                                - MyView => view # NSDictionary with class name 
/ object entry

You don't pass in the top-level objects, you receive them. Or, you can just not bother. An NSWindowController would manage this all for you. In any case, if you want to receive them with the loadNibFile:externalNameTable:withZone: method, you should pass an empty NSMutableArray in the external name table dictionary, under the NSNibTopLevelObjects key. The method would fill that array with the top-level objects.

Also, if you're using an NSWindowController in the typical way, it does not reside in the NIB, at all. Instead, the File's Owner (which, remember, is just a placeholder) is configured to be of the same class as your custom NSWindowController subclass. Configuring it in that way is just a means to get Interface Builder to know which outlets, actions, and properties it supports to assist you at design time. It has no real impact at runtime.

In this case, though, you want to pass your NSWindowController- subclass instance as the owner of the NIB when it's loaded. You don't pass or receive it as a top-level object, because it's not. It's not "in" the NIB, at all.

By the way, names of objects in Interface Builder are for human consumption only. They, too, have no runtime impact.


# I Also tried passing the object, and object-containing dictionaries below # e.g. dictionaryWithObjects_forKeys [NSApp, top_level, view], [NSNibOwner, NSNibTopLevelObjects, "My View"] context = NSDictionary::dictionaryWithObjects_forKeys [NSApp, top_level], [NSNibOwner, NSNibTopLevelObjects]

This is somewhat closer, except I believe you wanted your window controller to become the owner of the NIB. You're telling it to use the application object as the owner of the NIB, which doesn't match what you say you're trying to achieve. Also, it's not at all clear to me that top_level is the proper type of object. That's a matter for the RubyCocoa bridge, but loadNibFile:externalNameTable:withZone: is expecting an NSMutableArray instance for that key.

NibPath = ".../RandomAppRuby.app/Contents/Resources/English.lproj/ MainMenu.nib"
        
OSX::NSBundle::loadNibFile_externalNameTable_withZone NibPath, context, NSApp.zone

Regards,
Ken

_______________________________________________

Cocoa-dev mailing list ([email protected])

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to