objective-ccocoa-touchuilabelsubclassmessage-forwarding

Passing setters/getters of an instance variable up to a class


I'm working on creating a UIView subclass (which I'm calling MarqueeLabel) that animates a subview UILabel ivar in a marquee fashion when the UILabel text is too long for the containing view.

I was hoping to have a clean implementation, without having to write methods in my MarqueeLabel class just to set/retrieve all the the standard UILabel (text, font, color, etc) instance variables of the UILabel ivar. I've found a way to do this with message forwarding - all unrecognized methods sent to MarqueeLabel are passed on to the UILabel ivar. In my case the methods unrecognized by MarqueeLabel are the methods typically used with UILabel.

There are some problems with that approach though:
1. You have to use [marqueeLabel setText:@"Label here"], rather than marqueeLabel.text
2. The compiler gives warnings on the above line, because:

'MarqueeLabel' may not respond to '-setText:'

which I would know to ignore but would annoy anyone else.

To avoid these problems, is there any way to "bring forward" the methods an ivar so that they're accessible to something using the class while still acting upon the ivar object?

Thanks!

Note: The way I've set this up may not be the best way to do it either. Perhaps subclassing or class continuing UILabel would be better, but I wasn't able to grasp how the animation + clipping (when the text scrolling off moves out of containing UIView and disappears) could be done using those methods.

Note 2: I know you can use marqueeLabel.subLabel.text where subLabel is the subview UILabel. And this may be the direction I take, but might as well see if there's a better solution!


Solution

  • For properties, you could define a property in the interface and use @dynamic in the implementation so that you can don't have to create stub implementations. Make sure you also override valueForUndefinedKey: and setValue:forUndefinedKey: and forward to your label.

    For any methods which are not part of a property, you can use a category to declare the method without implementing it. This will get rid of warnings but still use the builtin forwarding.

    //MarqueeLabel.h
    #import <UIKit/UIKit.h>
    @interface MarqueeLabel : UIView {}
    @property (nonatomic, copy) NSString *text;
    @end
    @interface MarqueeLabel (UILabelWrapper)
    - (void)methodToOverride;
    @end
    
    //MarqueeLabel.m
    #import "MarqueeLabel.h"
    @implementation MarqueeLabel
    @dynamic text;
    - (id)valueForUndefinedKey:(NSString *)key {
        return [theLabel valueForKey:key];
    }
    - (void)setValue:(id)value forUndefinedKey:(NSString *)key {
        [theLabel setValue:value forKey:key];
    }
    @end