Передача параметров addTarget: действие: forControlEvents
Я использую addTarget: action: forControlEvents:
[newsButton addTarget:self
action:@selector(switchToNewsDetails)
forControlEvents:UIControlEventTouchUpInside];
и я хотел бы передать параметры моему селектору "switchToNewsDetails".
Единственное, что мне удалось сделать, это передать отправителя (id), написав:
action:@selector(switchToNewsDetails:)
Но я пытаюсь передать переменные как целочисленные значения. Написание этого способа не работает:
int i = 0;
[newsButton addTarget:self
action:@selector(switchToNewsDetails:i)
forControlEvents:UIControlEventTouchUpInside];
Запись этого способа тоже не работает:
int i = 0;
[newsButton addTarget:self
action:@selector(switchToNewsDetails:i:)
forControlEvents:UIControlEventTouchUpInside];
Любая помощь будет оценена:)
Ответы
Ответ 1
action:@selector(switchToNewsDetails:)
Здесь вы не передаете параметры switchToNewsDetails:
. Вы просто создаете селектор, чтобы кнопка могла вызвать ее, когда происходит определенное действие (коснитесь в вашем случае). Элементы управления могут использовать 3 типа селекторов для ответа на действия, все из которых имеют предопределенное значение их параметров:
-
без параметров
action:@selector(switchToNewsDetails)
-
с 1 параметром, указывающим элемент управления, который отправляет сообщение
action:@selector(switchToNewsDetails:)
-
С двумя параметрами, указывающими элемент управления, который отправляет сообщение и событие, вызвавшее сообщение:
action:@selector(switchToNewsDetails:event:)
Непонятно, что именно вы пытаетесь сделать, но учитывая, что вы хотите назначить конкретный индекс данных каждой кнопке, вы можете сделать следующее:
- установить свойство тега для каждой кнопки, равной требуемому индексу
-
в switchToNewsDetails:
вы можете получить этот индекс и открыть соответствующие файлы:
- (void)switchToNewsDetails:(UIButton*)sender{
[self openDetails:sender.tag];
// Or place opening logic right here
}
Ответ 2
Чтобы передать пользовательские параметры вместе с кнопкой, вам просто нужно SUBLASS UIButton.
(ASR включен, поэтому в коде нет релизов.)
Это myButton.h
#import <UIKit/UIKit.h>
@interface myButton : UIButton {
id userData;
}
@property (nonatomic, readwrite, retain) id userData;
@end
Это myButton.m
#import "myButton.h"
@implementation myButton
@synthesize userData;
@end
Использование:
myButton *bt = [myButton buttonWithType:UIButtonTypeCustom];
[bt setFrame:CGRectMake(0,0, 100, 100)];
[bt setExclusiveTouch:NO];
[bt setUserData:**(insert user data here)**];
[bt addTarget:self action:@selector(touchUpHandler:) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:bt];
Функция получения:
- (void) touchUpHandler:(myButton *)sender {
id userData = sender.userData;
}
Если вам нужно, чтобы я был более конкретным в любой части вышеуказанного кода, не стесняйтесь спрашивать об этом в комментариях.
Ответ 3
Target-Action позволяет три разных вида действия:
- (void)action
- (void)action:(id)sender
- (void)action:(id)sender forEvent:(UIEvent *)event
Ответ 4
Нужно больше, чем просто (int) через.tag? Используйте KVC!
Вы можете передавать любые нужные данные через сам объект кнопки (путем доступа к CALayers keyValue dict).
Установите свою цель следующим образом (с помощью ":")
[myButton addTarget:self action:@selector(buttonTap:) forControlEvents:UIControlEventTouchUpInside];
Добавьте ваши данные к самой кнопке (а именно к .layer
кнопки), например:
NSString *dataIWantToPass = @"this is my data";//can be anything, doesn't have to be NSString
[myButton.layer setValue:dataIWantToPass forKey:@"anyKey"];//you can set as many of these as you'd like too!
Затем, когда кнопка нажата, вы можете проверить это так:
-(void)buttonTap:(UIButton*)sender{
NSString *dataThatWasPassed = (NSString *)[sender.layer valueForKey:@"anyKey"];
NSLog(@"My passed-thru data was: %@", dataThatWasPassed);
}
Ответ 5
Я принял решение, частично основанное на приведенной выше информации. Я просто установил titlelabel.text в строку, которую я хочу передать, и установил titlelabel.hidden = YES
Вот так:
UIButton *imageclick = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
imageclick.frame = photoframe;
imageclick.titleLabel.text = [NSString stringWithFormat:@"%@.%@", ti.mediaImage, ti.mediaExtension];
imageclick.titleLabel.hidden = YES;
Таким образом, нет необходимости в наследовании или категории, и утечка памяти отсутствует.
Ответ 6
Я создавал несколько кнопок для каждого номера телефона в массиве, чтобы каждая кнопка нуждалась в другом номере телефона для вызова. Я использовал функцию setTag, поскольку я создавал несколько кнопок в цикле for:
for (NSInteger i = 0; i < _phoneNumbers.count; i++) {
UIButton *phoneButton = [[UIButton alloc] initWithFrame:someFrame];
[phoneButton setTitle:_phoneNumbers[i] forState:UIControlStateNormal];
[phoneButton setTag:i];
[phoneButton addTarget:self
action:@selector(call:)
forControlEvents:UIControlEventTouchUpInside];
}
Тогда в моем методе call: я использовал тот же для цикла и оператор if, чтобы выбрать правильный номер телефона:
- (void)call:(UIButton *)sender
{
for (NSInteger i = 0; i < _phoneNumbers.count; i++) {
if (sender.tag == i) {
NSString *callString = [NSString stringWithFormat:@"telprompt://%@", _phoneNumbers[i]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:callString]];
}
}
}
Ответ 7
Как есть много способов, упомянутых здесь для решения, кроме функции категории.
Используйте функцию категории для расширения определенного (встроенного) элемента в свой настраиваемый элемент.
Например (ex):
@interface UIButton (myData)
@property (strong, nonatomic) id btnData;
@end
в вашем представлении Controller.m
#import "UIButton+myAppLists.h"
UIButton *myButton = // btn intialisation....
[myButton set btnData:@"my own Data"];
[myButton addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
Обработчик событий:
-(void)buttonClicked : (UIButton*)sender{
NSLog(@"my Data %@", sender. btnData);
}
Ответ 8
Есть еще один способ, которым вы можете получить indexPath ячейки, в которой была нажата ваша кнопка:
используя обычный селектор действий, как:
UIButton *btn = ....;
[btn addTarget:self action:@selector(yourFunction:) forControlEvents:UIControlEventTouchUpInside];
а затем в вашей функции:
- (void) yourFunction:(id)sender {
UIButton *button = sender;
CGPoint center = button.center;
CGPoint rootViewPoint = [button.superview convertPoint:center toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:rootViewPoint];
//the rest of your code goes here
..
}
так как вы получаете indexPath, это стало намного проще.
Ответ 9
См. мой комментарий выше, и я считаю, что вам нужно использовать NSInvocation, когда имеется более одного параметра
дополнительную информацию о NSInvocation здесь
http://cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html
Ответ 10
Это исправило мою проблему, но она разбилась, если я не изменил
action:@selector(switchToNewsDetails:event:)
к
action:@selector(switchToNewsDetails: forEvent:)
Ответ 11
Вы можете заменить целевое действие закрытием (блок в Objective-C), добавив оболочку закрывающего закрытия (ClosureSleeve) и добавив ее в качестве связанного объекта к элементу управления, чтобы он остался. Таким образом, вы можете передать любые параметры.
Swift 3
class ClosureSleeve {
let closure: () -> ()
init(attachTo: AnyObject, closure: @escaping () -> ()) {
self.closure = closure
objc_setAssociatedObject(attachTo, "[\(arc4random())]", self, .OBJC_ASSOCIATION_RETAIN)
}
@objc func invoke() {
closure()
}
}
extension UIControl {
func addAction(for controlEvents: UIControlEvents, action: @escaping () -> ()) {
let sleeve = ClosureSleeve(attachTo: self, closure: action)
addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
}
}
Использование:
button.addAction(for: .touchUpInside) {
self.switchToNewsDetails(parameter: i)
}
Ответ 12
Я подклассифицировал UIButton в CustomButton, и я добавляю свойство, в котором храню свои данные. Поэтому я вызываю метод: (CustomButton *) отправитель и в методе я только читаю мои данные sender.myproperty.
Пример CustomButton:
@interface CustomButton : UIButton
@property(nonatomic, retain) NSString *textShare;
@end
Действие метода:
+ (void) share: (CustomButton*) sender
{
NSString *text = sender.textShare;
//your work…
}
Назначить действие
CustomButton *btn = [[CustomButton alloc] initWithFrame: CGRectMake(margin, margin, 60, 60)];
// other setup…
btnWa.textShare = @"my text";
[btn addTarget: self action: @selector(shareWhatsapp:) forControlEvents: UIControlEventTouchUpInside];
Ответ 13
Если вы просто хотите изменить текст для leftBarButtonItem, отображаемый контроллером навигации вместе с новым представлением, вы можете изменить заголовок текущего представления непосредственно перед вызовом pushViewController на нужный текст и восстановить его в обратном вызове viewHasDisappered для будущих отображений текущий вид.
Этот подход сохраняет функциональность (popViewController) и появление показанной стрелки нетронутыми.
У нас это работает по крайней мере с iOS 12, построенной с Xcode 10.1...