On Sep 22, 2008, at 3:51 PM, Dalzhim Dalzhim wrote:
2008/9/22 Jonathan Hess
<email@hidden>
Hey Dalzhim -
If you want to work with your Interface Builder outside of building and running your plug-in project, you need to do an "sudo xcodebuild install" from your project directory and then install the built bits. By default, Xcode will layout the distribution root for the built projects in /tmp in a folder that starts with the name of your projects and ends with dst. If you examine this folder, you'll see that it's a sparse root for /. It will contain all of the files your project built that should be installed and the will have a path relative to their final destination. If your project was named MyProject, you could install them with 'sudo ditto /tmp/MyProject.dst/ /'. That ditto command would overlay the contents of the distribution root on to /, effectively installing them. At this point if you launched Interface Builder from the finder, you'd be able to load your plug-in and work with it. Working with your plug-in in this manner would be different than working with it after having pressed build and run from the plug-in project in Xcode. Pressing build and run will build and run the latest sources. When running IB from the finder, you'll be running against the installed framework, and possibly the installed plug-in depending on which on you loaded into Interface Builder last.
Hello Jon,
I have seen some discussions where this "sudo xcodebuild install" procedure was explained but I thought this was meant for a permanent installation of a plugin (which I meant to do much later in my development process). From what I have read in the Interface Builder Plug-In Programming Guide, I thought it was possible to dynamically load plug-ins when they were in the Resources folder of a linked-in framework.
Hey Dalzhim -
IB does automatically load the plug-ins embedded in the resources of frameworks that are linked by your project, but it still depends on those plug-ins and their frameworks living at their installed location. The problem you're experiencing is because the framework and plug-in are in your build directory, not their installed location. The "sudo xcodebuild install" followed by the ditto places a copy of the frameworks and plug-ins in their installed locations.
It should be possible to configuring the @rpath settings of your plugin so that it can be loaded either from the build directory or the install location and always find the nearby framework. However, I don't know enough about rpath relative linking to give you explicit instructions.
When your code is in IB, and is working with images there are a couple of subtleties to consider. First, is the image a project image coming from the user, or is it a framework image coming from your framework, or both. If your widget has an image property, that you would like the user to be able to fill out in the inspector, then you should obtain the image via -[IBDocument documentImageNamed:]. The reason you need to go through that message and not -[NSImage imageNamed:] is that -[NSImage imageNamed:] works on a global set of names. In Interface Builder the user is free to work on many documents were each document has a different set of images and names. Unfortunately, Interface Builder doesn't offer a way for plug-ins to integrate content into the set of per-document named images. So, if you're framework has an image and you want that image to show up in the library and be available to regular cocoa controls, then unfortunately, there isn't a supported way to do that. However, if you just want to integrate the users images into your custom controls, you should be able to do that with -[IBDocument documentImageNamed:].
Jon Hess
I have tried using -[IBDocument documentImageNamed:] without success as I have never succeeded on getting an instance of IBDocument. I have tried getting an instance using +[IBDocument documentForObject:] from within MyComponent but the only result I have ever had was nil.
The object you pass in as the argument to documentForObject: needs to be one of the objects that appears in the document outline view in Interface Builder. If [IBDocument documentForObject:object] is returning nil, then that means the object you passed in as an argument isn't in a document. For example, it would return nil if you passed in your inspector, or a private helper object of your view that isn't in your Interface Builder document. -[IBInspector document] is an alternative way to retrieve the inspected document.
If the object I was integrating was a 'MyView' and it had an image property, I might implement it like this.
@implementation MyWidget(IBInspectorAdditions)
- (NSString *)inspectedImageName {
return [[self image] image];
}
- (void)setInspectedImageName:(NSString *)name {
IBDocument *document = [IBDocument documentForObject:self];
[self willChangeValueForKey:@"inspectedImageName"];
[self setImage:[document documentImageNamed:name]];
[self didChangeValueForKey:@"inspectedImageName"];
}
@end
Then I would bind my inspector to the File's Owner's "inspectedObjectsController.selection.inspectedImageName".
I only used those two lines from within the setter method for the image property of MyComponent and upon every modification of this property through the inspector view I have made, debugging showed I never had a IBDocument instance.
IBDocument* doc = [IBDocument documentForObject:self];
NSImage* image = [doc documentImageNamed:imageName];
What am I doing wrong?
Thanks for your help!
That code looks fine, it must be the case that 'self' isn't a object in an IBDocument. Do you see it in the outline view of the document window?
Jon Hess
regards
-Dalzhim