Reputation: 83
I've read, that when you want to identify a button that has been clicked you can simply use
button.tag = 10
as an example. The problem I'm occuring now, is, that I need to use a string as identifier, since the id comes from a server, that uses words and numbers in its identifier to make it unique. The problem I have now, is that I don't really now how I could identify the button since tag is only for integers. I can't just iterate it because it has to be fully dynamic. What would be the way to go?
I've read this link right here How to pass a string as a tag of UIButton
and it said something of subclasses, but I'm fairly new to Objective-C so I don't know if that's to haard for a beginner!
Edit of the code after suggestions from user @Greg
//Class: CustomButton.h
@interface CustomButton : UIButton
@property ( nonatomic, retain ) NSString *stringTag;
@end
//Class: MainViewController.m
#import "CustomButton.h"
//code
CustomButton *testButton = [CustomButton buttonWithType:UIButtonTypeRoundedRect];
testButton.frame = CGRectMake( 15.0f, _counterForLists, 250.0f, 30.0f );
[testButton addTarget :self action:@selector( deleteListItem:) forControlEvents:UIControlEventTouchUpInside];
[testButton setBackgroundColor :[UIColor blackColor]];
[testButton setTitleColor :[UIColor whiteColor] forState:UIControlStateNormal];
[testButton setTitle :[projectData description] forState:UIControlStateNormal];
testButton.stringTag = @"TEST";
_counterForLists += 30;
[self.view addSubview:testButton ];
//Method deleteListItem (When I press the button it crashes)
- (void)deleteListItem:(CustomButton *)sender{
NSLog(@"Button clicked with ID: %@", sender.stringTag);
}
Upvotes: 0
Views: 137
Reputation: 12103
No need to create a whole new class that subclasses UIButton
if we're just adding a new property we can just create a new category for UIButton
by doing the following:
UIButton+properties_cat.h
#import <UIKit/UIButton.h>
#import <objc/runtime.h>
@interface UIButton (properties_cat)
@property (nonatomic, strong) NSString *nameTag;
@end
UIButton+properties_cat.h
#import "UIButton+properties_cat.h"
@implementation UIButton (properties_cat)
// We can't use synthesize with categories so we have to use dynamic.
@dynamic nameTag;
#pragma mark - Setters and Getters for nameTag Property
- (void)setNameTag:(NSString *)nameTag
{
objc_setAssociatedObject(self, @"nameTag", nameTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)nameTag
{
return objc_getAssociatedObject(self, @"nameTag");
}
@end
Then make sure to import the new class into your code by doing #import "UIButton+properties_cat.h"
Once we have #imported
it we can now use it in that class like so
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setNameTag:@"my button name"];
Notice that we are still using UIButton
and not created a pointless new class like MyButton
we have just added that new property (nameTag
) to the existing UIButton
class.
UPDATE
This is an update based on comments in another answer.
So you want to be able to access a button that you have done in another method?
Well lets improve the code from above. Instead of applying the nameTag
to UIButton
lets apply it to UIView
which UIButton
inherits from. This will then allow us to apply nameTag
to anything that inherits from UIView
- UILabel
, UIButton
etc.
We also want to implement a new method called viewWithName:
this will work the same way as viewWithTag:
except it will check the nameTag
instead of the tag
.
So try using the following code:
UIView+cat.h
#import <UIKit/UIView.h>
#import <objc/runtime.h>
@interface UIView (cat)
@property (nonatomic, strong) NSString *nameTag;
- (UIView *)viewWithName:(NSString *)name;
@end
UIView+cat.m
#import "UIView+cat.h"
@implementation UIView (cat)
@dynamic nameTag;
#pragma mark - viewWithName: method
- (UIView *)viewWithName:(NSString *)name
{
for(id view in [self subviews]) {
// This if statement checks that the view is an instance of UIView class
// or inherits from it, so it should return true if like UILabel.
if([view isKindOfClass:[UIView class]]) {
if([[view nameTag] isEqualToString:name]) {
// This will return the first view that it comes across with the nameTag that equals name
return view;
}
}
}
return nil;
}
#pragma mark - Setters and Getters for nameTag Property
- (void)setNameTag:(NSString *)nameTag
{
objc_setAssociatedObject(self, @"nameTag", nameTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)nameTag
{
return objc_getAssociatedObject(self, @"nameTag");
}
@end
Now instead of importing UIButton+properties_cat.h
we need to import UIView+cat.h
this is because we don't need to create UIButton+properties_cat.h
as UIButton
inherits from UIView
so it will pick the new property and method up.
So once we have imported UIView+cat.h
we can then set our UIButton
nameTag
like:
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setNameTag:@"my button name"];
then in another method that we want to access that button in we can do
UIButton *btn = (UIButton *)[[self view] viewWithName:@"my button name"];
We add the cast because viewWithName:
will return a UIView
we want to make sure it is an instance of UIButton
.
More information on Customizing Classes with Categories
If you need any more just ask.
Upvotes: 2
Reputation: 25459
You can create subclass of UIButton and add a identifier property:
@interface MyButton : UIButton
@property (nonatomic, strong) NSString *tagAsString;
@end
And every time where you use UIButton replace it with MyButton, for example: Old code
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setFrame:CGRectMake(0.0f, 0.0f, 50, 30)];
[btn setTitle:@"Your title" forState:UIControlStateNormal];
btn.tag = 1;
[btn addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view btn];
with:
MyButton *btn = [MyButton buttonWithType:UIButtonTypeRoundedRect];
[btn setFrame:CGRectMake(0.0f, 0.0f, 50, 30)];
[btn setTitle:@"Your title" forState:UIControlStateNormal];
btn.tagAsString = @"string as a identifier";
[btn addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view btn];
And you can still use tag property.
//EXTENDED
You cannot use standard method like viewWithTag:, you should create your own, for example:
-(MyButton*)buttonForTag:(NSString*)tagAsString
{
for (UIView *v in self.view.subviews)
{
if ([v isKindOfClass:[MyButton class]])
{
MyButton *btn = (MyButton*)v;
if ([btn.tagAsString isEqualToString:tagAsString])
return btn;
}
}
}
Hope this help.
Upvotes: 0
Reputation: 20410
The tag could only be an integer, if you need to use a NSString as identifier you have to subclass UIButton, add a new NSString property called buttonID (for example) and use that button.
Upvotes: 0