Alternative / Similar to tag in UIView

Go To StackoverFlow.com

0

Is there any alternative to use like tag to property of UIView? The thing is I'd like to pass UITextField some NSInteger. Way to do is tag. But I want to pass 2 different NSInteger.

Any ideas?

2012-04-04 03:08
by HelmiB


3

You could subclass UITextField and add two NSInteger properties to the class.

@interface CustomTextField : UITextField

@property (nonatomic, assign) NSInteger x;
@property (nonatomic, assign) NSInteger y;

@end
2012-04-04 03:12
by Michael Frederick
+1 I was about to say the same thing. : - lnafziger 2012-04-04 03:12


2

You can attach any data to any object using an Associative Reference. This is a very handy approach. It even correctly handles memory management. I sometimes use a category to wrap these so I can create new properties on an existing class. For example, in one project I'd like every view controller to know about a special label (like how they all know about navigationController). I do it this way:

@interface UIViewController (MYSpecialViewController)
@property (nonatomic, readwrite, strong) UILabel *specialLabel;
@end

@implementation UIViewController (MYSpecialViewController)
static const char kMySpecialLabelKey;

- (UILabel *)specialLabel
{
  return objc_getAssociatedObject(self, &kMySpecialLabelKey);
}

- (void)setSpecialabel:(UILabel *)value
{
  objc_setAssociatedObject(self, &kMySpecialLabelKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

You can find a simple working example using a UIAlertView in the iOS5:PTL sample code for Chapter 3.

2012-04-04 03:20
by Rob Napier
I made a couple of small edits, I hope you don't mind. Previously it would have used the static pointer value, which would be 0. Now it's a pointer to a static char, which will have a meaningful address - Sedate Alien 2012-04-04 03:41
@SedateAlien Thanks. You're completely correct. This was a bug in the code I was referencing (so I've now fixed my product code). The sample code referenced does it correctly. As you note, this should be a char, not a char* - Rob Napier 2012-04-04 03:47
What is the benefit of doing this -vs- subclassing - lnafziger 2012-04-04 04:09
pardon me, but how to add primitive data type ? such as NSInteger / int - HelmiB 2012-04-04 06:17
@Inafziger Subclassing has many limitations. Consider the above example. I want every UIViewController to have this functionality. Obviously I could make MYViewController and subclass from that, but what if I want UITableViewViewControllers, too? There's nowhere to inject the code in that case without duplicating the properties. (This was the exact reason for the code above, btw; it was originally a subclass.) This also works with classes that can't safely be subclassed, and with instances generated by the frameworks - Rob Napier 2012-04-04 13:59
@HelmiB The best solution usually would be to wrap it in an NSNumber. But, you can also store anything that is the size of a pointer as long as you pass the behavior OBJCASSOCIATIONASSIGN. Just be careful that you know the correct size for a pointer (NSInteger and CGFloat are useful for this since they are always pointer-sized) - Rob Napier 2012-04-04 14:05
@RobNapier I got the error of doing so. could you please add up your answer to use NSInteger - HelmiB 2012-04-05 00:51
Let me guess; you're running under ARC? You could add the required cast (__bridge id), but that's starting to get ugly if you don't deeply know what you're doing. It really takes an id, so pass one. Just wrap the integer in an NSNumber - Rob Napier 2012-04-05 02:33
Associative references are more documented here: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html#//apple_ref/doc/uid/TP30001163-CH2 - SeikoTheWiz 2018-11-08 16:02


1

Take the general, object-oriented solution, but remember you can a stuff lot of data into a tag:

- (uint32_t)pack:(uint16_t)a with:(uint16_t)b {

  return (uint32_t)(a << 16 | b);
}

- (uint16_t)getA:(uint32_t)pair {
    return (uint16_t)((pair & 0xffff0000) >> 16);
}

- (uint16_t)getB:(uint32_t)pair {
    return (uint16_t)(pair & 0xffff);
}

// use it

- (void)setupSomeView {

    someView.tag = [self pack:1024 with:2048];
}

- (IBAction)someControlEventHappened:(id)sender {

    NSLog(@"%d %d", [self getA:sender.tag], [self getB:sender.tag]);
}

Caveats:

  1. @RobNapier's answer is more general, more correct. The only advantage this way is that it's quick and dirty
  2. Works for pairs of unsigned ints < 32k
  3. Works NSInteger implementations >= 32 bits, which is everywhere, I think.
2012-04-04 04:17
by danh
Ads