Re: self registering NSValueTransformer and bindings
Re: self registering NSValueTransformer and bindings
- Subject: Re: self registering NSValueTransformer and bindings
- From: Torsten Curdt <email@hidden>
- Date: Thu, 8 May 2008 12:53:36 +0200
On May 7, 2008, at 19:32, I. Savant wrote:
I have a self registering NSValueTransformer that requires a binding.
Did you mean it's required for use in a binding?
Well, maybe it's language barrier as a non-native speaker ...but in
order for the transformer to do its job it requires a reference to the
NSTabView to be set. And I was trying to inject that reference through
a binding. That's what I wanted to say.
@interface MyValueTransformer : NSValueTransformer {
IBOutlet NSTabView *tabView;
}
That's probably not going to work out ... (see below)
// from http://www.gigliwood.com/weblog/
+ (void)load
{
NSLog(@"registered %@", NSStringFromClass([self class]));
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSValueTransformer *theTransformer = [[[self alloc] init]
autorelease];
[NSValueTransformer setValueTransformer:theTransformer
forName:NSStringFromClass([self class])];
[pool release];
}
See:
http://developer.apple.com/documentation/Cocoa/Conceptual/ValueTransformers/Concepts/Registration.html
Read that :)
Here you're instantiating an instance of the generic
NSValueTransformer class and letting the NSValueTransformer class know
that it should use that generic transformer any time
"MyValueTransformer" is requested.
That does not seem to be true. But to be 100% sure I've changed it to
NSValueTransformer *theTransformer = [[[MyValueTransformer alloc]
init] autorelease];
...and still get the same behavior. The correct instance is always a
MyValueTransformer and no NSValueTransformer as you said.
I've instantiate it through the NIB. Which works fine! I do see the
NSLog
lines and all.
I'm not sure how that's happening, given the above. I would expect
your transform method not to be called at all, given the above. I
could be wrong, then again it's not working right for you, so it's
worth checking out. ;-)
No, that's all working fine. See above.
Unfortunately the IBOutlet stays nil ...but in the bindings
inspector I can
see the proper binding on the transformer.
I don't know what you mean about 'the proper binding', but no, I
wouldn't expect the outlet to be anything but nil. The *instance* you
*instantiated* in your nib is not the same one you're passing when
registering the transformer for the name "MyValueTransformer". In
*that* instance, the outlet is nil.
Doh! ...now here I was really stupid. But then again I would think
changing it to
- (void) awakeFromNib
{
NSLog(@"registered %@", NSStringFromClass([self class]));
[NSValueTransformer setValueTransformer:self
forName:NSStringFromClass([self class])];
}
would solve it. Turns out this is not enough. From looking at the
stacktrace it seems like the framework seems to create another
instance. So the only way I could get it to work was to register the
transformer in the init.
- (id) init
{
self = [super init];
if (self != nil) {
NSLog(@"new %@ (%@)", NSStringFromClass([self class]), self);
[NSValueTransformer setValueTransformer:self
forName:NSStringFromClass([self class])];
}
return self;
}
This way I end up just with the one instance created from the NIB.
Perhaps in some -awakeFromNib method you could ask
NSValueTransformer for the transformer for the name
"MyValueTransformer" and set its outlet then (you'd need a 'setter'
accessor method) ... but what you're doing is strange.
A value transformer really shouldn't know anything about a tab view.
Well, that depends ...see below
Its sole job is to transform one value to another. A number to a
string, or a class name to an image, etc. and possibly vice-versa
(reverse transformations). Why does yours care about a tab view?
Perhaps all you want is a few constants that's included into your
transformer via a header include ...
That is one way and I've already got it working like that.
...
That header can be included in your
AccountTypeToSelectedTabTransformer ... where it gives the correct tab
index depending on whether the passed value is kNormalAccountType or
kSuperHappyFunLuckyMegaAccountType or some other ridiculous example.
Keeps everything simple, straight-forward, and easy to read months
later when you decide to modify it.
Well, my account types have declarative names instead of defined
numbers. So the transformer basically does
- (id)transformedValue:(id)value
{
if ([@"accountType1" isEqualToString:value]) {
return [NSNumber numberWithInt:1];
}
...
And I think this could be quite neatly be abstracted away if the
transformer had access to the NSTabView. The name of the tab would be
the name of the account type the transformer is mapping to. Not such a
weird idea IMO. But it requires the transformer to have a reference to
the NSTabView. I could manually inject it - but using a NIB and using
bindings felt more natural (to me). It would make the transformer much
more re-usable ...so I was trying
I wouldn't expect the reference to be set in awakeFromNib ....but I
would expect it to be set later on when transformedValue is getting
called. And that actually seems to work fine now :-D
Does that make a little more sense now?
One thing that is still missing is to get multiple instances working.
So basically getting rid of "NSStringFromClass([self class])" and
replace that with data from the object's interface builder identity.
But somehow I doubt that's easily accessible ...is it?
cheers
--
Torsten
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden