Truyền tham số cho addTarget: action: forControlEvents


125

Tôi đang sử dụng addTarget: action: forControlEvents như thế này:

[newsButton addTarget:self
action:@selector(switchToNewsDetails)
forControlEvents:UIControlEventTouchUpInside];

và tôi muốn chuyển tham số cho bộ chọn "switchToNewsDetails" của mình. Điều duy nhất tôi thành công trong việc làm là vượt qua người gửi (id) bằng cách viết:

action:@selector(switchToNewsDetails:)

Nhưng tôi đang cố gắng truyền các biến như giá trị nguyên. Viết theo cách này không hiệu quả:

int i = 0;
[newsButton addTarget:self
action:@selector(switchToNewsDetails:i)
forControlEvents:UIControlEventTouchUpInside];

Viết nó theo cách này cũng không hoạt động:

int i = 0;
[newsButton addTarget:self
action:@selector(switchToNewsDetails:i:)
forControlEvents:UIControlEventTouchUpInside];

Bất kỳ trợ giúp sẽ được đánh giá cao :)


Chữ ký phương thức cho switchToNewsDetails là gì?
Aaron Saunders

- (void) switchToNewsDetails: (id) người gửi; - (void) switchToNewsDetails: (int) i: (id) người gửi;
Pierre Espenan

Nhưng những gì tôi phụ thuộc vào? nó là cụ thể cho từng nút? Xem câu trả lời của tôi - không phải thuộc tính thẻ là những gì bạn cần?
Vladimir


@PierreEspenan Câu trả lời được chấp nhận hiện tại của bạn chỉ cho phép chuyển số nguyên qua thẻ rất hạn chế. Tôi đề nghị bạn thay đổi nó thành câu trả lời của tôi cho phép vượt qua bất kỳ đối tượng nào. stackoverflow.com/a/40051706/2057171
Albert Renshaw

Câu trả lời:


173
action:@selector(switchToNewsDetails:)

Bạn không truyền tham số cho switchToNewsDetails:phương thức ở đây. Bạn chỉ cần tạo một bộ chọn để làm cho nút có thể gọi nó khi hành động nhất định xảy ra (chạm vào trong trường hợp của bạn). Điều khiển có thể sử dụng 3 loại bộ chọn để phản hồi hành động, tất cả chúng đều có ý nghĩa được xác định trước của các tham số:

  1. không có tham số

    action:@selector(switchToNewsDetails)
  2. với 1 tham số cho biết điều khiển gửi tin nhắn

    action:@selector(switchToNewsDetails:)
  3. Với 2 tham số cho biết điều khiển gửi tin nhắn và sự kiện đã kích hoạt tin nhắn:

    action:@selector(switchToNewsDetails:event:)

Không rõ chính xác những gì bạn cố gắng làm, nhưng xem xét bạn muốn chỉ định một chỉ số chi tiết cụ thể cho từng nút, bạn có thể làm như sau:

  1. đặt thuộc tính thẻ cho mỗi nút bằng chỉ mục yêu cầu
  2. trong switchToNewsDetails:phương thức bạn có thể có được chỉ mục đó và mở các đoạn mã thích hợp:

    - (void)switchToNewsDetails:(UIButton*)sender{
        [self openDetails:sender.tag];
        // Or place opening logic right here
    }
    

4
Điều gì xảy ra nếu chúng ta cố gắng vượt qua thứ gì đó ngoài số nguyên? Nếu tôi cần truyền một đối tượng như một chuỗi thì sao?
user102008

@user bối cảnh của bạn là gì? Có vẻ bạn sẽ cần phải vượt qua nó một cách riêng biệt
Vladimir

cảm ơn rất nhiều. bạn đã tìm thấy dữ liệu này ở đâu? Tôi luôn đánh giá cao tài liệu tham khảo để có thể tôi có thể tìm thấy nó vào lần tới.
bearMenez

1
@bearMenez bạn có thể kiểm tra liên kết này: developer.apple.com/l Library / mac / # document / Cocoa / Conceptionual / ví dụ
Vladimir

3
Bạn không cần phải vượt qua nó một cách riêng biệt. Nếu bạn đang vượt qua bất kỳ NSObject nào, bạn chỉ có thể nói [button.layer setValue:yourObject forKey:@"anyKey"];và sau đó trong phương thức, chỉ cần kiểm tra (objectClass *)[button.layer valueForKey:@"anyKey"];Nó giống như một phiên bản miễn phí hơn của.tag
Albert Renshaw

64

Để vượt qua các thông số tùy chỉnh cùng với nút bấm, bạn chỉ cần SUBCLASS UIButton .

(ASR được bật, vì vậy không có bản phát hành nào trong mã.)

Đây là myButton.h

#import <UIKit/UIKit.h>

@interface myButton : UIButton {
    id userData;
}

@property (nonatomic, readwrite, retain) id userData;

@end

Đây là myButton.m

#import "myButton.h"
@implementation myButton
@synthesize userData;
@end

Sử dụng:

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];

Chức năng nhận:

- (void) touchUpHandler:(myButton *)sender {
    id userData = sender.userData;
}

Nếu bạn cần tôi nói cụ thể hơn về bất kỳ phần nào của đoạn mã trên - vui lòng hỏi về nó trong các bình luận.


Tôi nghĩ rằng đây là cách tốt nhất
Çağatay Gürtürk

Giải pháp thanh lịch nhất.
Victor C.

2
Câu trả lời tuyệt vời ... rất tùy biến. Chính xác những gì tôi đang tìm kiếm. MOLODETS! :)
denikov

cảm ơn vì đã phản hồi :) Rất vui vì nó hữu ích cho ai đó :)
Yuriy Polarzhayev

1
Cách giải quyết đơn giản và hữu ích. Chỉ cần để tôi thêm rằng điều này tương tự như tagtài sản trong chế độ xem Android . Họ có thể lưu trữ bất kỳ đối tượng. Và bạn cũng có thể lưu trữ các đối tượng theo khóa như trong Từ điển / Bản đồ.
Ferran Maylinch

19

Target-Action cho phép ba hình thức chọn hành động khác nhau:

- (void)action
- (void)action:(id)sender
- (void)action:(id)sender forEvent:(UIEvent *)event

16

Cần nhiều hơn chỉ là một (int) thông qua .tag? Sử dụng KVC!

Bạn có thể truyền bất kỳ dữ liệu nào bạn muốn thông qua chính đối tượng nút (bằng cách truy cập chính tả của CALayers keyValue dict).


Đặt mục tiêu của bạn như thế này (với ":")

[myButton addTarget:self action:@selector(buttonTap:) forControlEvents:UIControlEventTouchUpInside];

Thêm (các) dữ liệu của bạn vào chính nút đó (cũng .layerlà nút đó) như thế này:

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!

Sau đó, khi nhấn nút, bạn có thể kiểm tra nó như thế này:

-(void)buttonTap:(UIButton*)sender{

    NSString *dataThatWasPassed = (NSString *)[sender.layer valueForKey:@"anyKey"];
    NSLog(@"My passed-thru data was: %@", dataThatWasPassed);

}

không có phương thức nào trong UIButton.layer để đặt hoặc thêm một đối tượng. Bạn lấy giải pháp đó ở đâu?
mAc

1
Một UIButton là một loại UIView, tất cả các UIView đều có thuộc tính .Layer. CALayer chứa các hành vi NSDipedia. Lưu ý đây là Objective-C không phải Swift, đó có thể là vấn đề? Dưới đây là Tài liệu của Apple về mã hóa khóa-giá trị CALayer: developer.apple.com/l
Library

1
Đây phải là câu trả lời trên đầu trang. Cho đến nay cách dễ nhất để làm điều đó!. cảm ơn!
danielrosero

1
Nó nên được chấp nhận câu trả lời. Cách dễ dàng và thông minh hơn nhiều.
Emon

1
Câu trả lời chính xác! Ước gì tôi biết điều này từ lâu.
Giăng

7

Tôi đã thực hiện một giải pháp dựa một phần bởi các thông tin trên. Tôi chỉ đặt Titlelabel.text thành chuỗi tôi muốn vượt qua và đặt Titlelabel.hidden = YES

Như thế này :

UIButton *imageclick = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
imageclick.frame = photoframe;
imageclick.titleLabel.text = [NSString stringWithFormat:@"%@.%@", ti.mediaImage, ti.mediaExtension];
imageclick.titleLabel.hidden = YES;

Bằng cách này, không cần thừa kế hoặc danh mục và không có rò rỉ bộ nhớ


5

Tôi đã tạo một số nút cho mỗi số điện thoại trong một mảng để mỗi nút cần một số điện thoại khác nhau để gọi. Tôi đã sử dụng hàm setTag khi tôi đang tạo một số nút trong vòng lặp 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];
}

Sau đó, trong cuộc gọi của tôi: phương thức tôi đã sử dụng tương tự cho vòng lặp và một câu lệnh if để chọn đúng số điện thoại:

- (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]];
        }
    }
}

bạn có thể cải thiện mã này:- (void)call:(UIButton *)sender { NSString *phoneNumber = _phoneNumbers[i]; NSString *callString = [NSString stringWithFormat:@"telprompt://%@", phoneNumber]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:callString]]; }
Ladessa

2

Vì có nhiều cách được đề cập ở đây cho giải pháp, ngoại trừ tính năng danh mục.

Sử dụng tính năng danh mục để mở rộng phần tử được xác định (tích hợp) vào thành phần tùy chỉnh của bạn.

Ví dụ: ví dụ:

@interface UIButton (myData)

@property (strong, nonatomic) id btnData;

@end

trong chế độ xem của bạn Trình điều khiển.m

 #import "UIButton+myAppLists.h"

UIButton *myButton = // btn intialisation....
 [myButton set btnData:@"my own Data"];
[myButton addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];

Xử lý sự kiện:

-(void)buttonClicked : (UIButton*)sender{
    NSLog(@"my Data %@", sender. btnData);
}

Bạn thực sự không thể thêm thuộc tính trong danh mục.
HotFudgeSunday

2

Bạn có thể thay thế hành động đích bằng một bao đóng (khối trong Objective-C) bằng cách thêm một trình bao bọc đóng của trình trợ giúp (ClosSleeve) và thêm nó dưới dạng một đối tượng liên quan vào điều khiển để nó được giữ lại. Bằng cách đó bạn có thể vượt qua bất kỳ tham số.

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)
    }
}

Sử dụng:

button.addAction(for: .touchUpInside) {
    self.switchToNewsDetails(parameter: i)
}

Phương pháp trên ( self.switchToNewsDetails(parameter: i)) bắn 2 lần, tại sao giúp tôi thoát ra
Nagendar

Mã làm việc cho tôi. Đã thử nghiệm trong dự án Ứng dụng xem đơn mới pastebin.com/tPaqetMb . Vì vậy, vấn đề có thể nằm ở mã của bạn, như gọi button.addAction()hai lần. Thêm một điểm dừng button.addActionvà cũng trên dòng đầu tiên bên trong bao đóng và cố gắng tự gỡ lỗi nó.
Marián Černý

2

Có một cách khác, trong đó bạn có thể lấy indexPath của ô nơi nhấn nút của bạn:

sử dụng bộ chọn hành động thông thường như:

 UIButton *btn = ....;
    [btn addTarget:self action:@selector(yourFunction:) forControlEvents:UIControlEventTouchUpInside];

và sau đó trong Hàm của bạn:

   - (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
    ..
}

kể từ khi bạn nhận được một indexPath, nó trở nên đơn giản hơn nhiều.


1

Xem nhận xét của tôi ở trên và tôi tin rằng bạn phải sử dụng NSInvocation khi có nhiều hơn một tham số

thêm thông tin về NSInvocation tại đây

http://cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html


Trên thực tế, tôi không muốn vượt qua một vài thông số, tôi chỉ muốn một số nguyên.
Pierre Espenan

trên thực tế có phương thức PerformanceSelector: withObject: withObject: cho phép gọi các bộ chọn với 2 tham số. Nhưng để biết thêm bạn cần NSInvocation
Vladimir

1

Điều này đã khắc phục sự cố của tôi nhưng nó đã bị sập trừ khi tôi thay đổi

action:@selector(switchToNewsDetails:event:)                 

đến

action:@selector(switchToNewsDetails: forEvent:)              

0

Tôi đã phân lớp UIButton trong CustomButton và tôi thêm một thuộc tính nơi tôi lưu trữ dữ liệu của mình. Vì vậy, tôi gọi phương thức: (CustomButton *) người gửi và trong phương thức tôi chỉ đọc người gửi dữ liệu của mình.myproperty.

Ví dụ CustomButton:

@interface CustomButton : UIButton
@property(nonatomic, retain) NSString *textShare;
@end

Phương thức hành động:

+ (void) share: (CustomButton*) sender
{
    NSString *text = sender.textShare;
    //your work…
}

Chỉ định hành động

    CustomButton *btn = [[CustomButton alloc] initWithFrame: CGRectMake(margin, margin, 60, 60)];
    // other setup…

    btnWa.textShare = @"my text";
    [btn addTarget: self action: @selector(shareWhatsapp:)  forControlEvents: UIControlEventTouchUpInside];

0

Nếu bạn chỉ muốn thay đổi văn bản cho leftBarButtonItem được hiển thị bởi trình điều khiển điều hướng cùng với chế độ xem mới, bạn có thể thay đổi tiêu đề của chế độ xem hiện tại ngay trước khi gọi PushViewContoder thành văn bản mong muốn và khôi phục nó trong chế độ gọi lại trong tương lai quan điểm hiện tại.

Cách tiếp cận này giữ cho chức năng (popViewControll) và sự xuất hiện của mũi tên được hiển thị nguyên vẹn.

Nó hoạt động với chúng tôi ít nhất là với iOS 12, được xây dựng với Xcode 10.1 ...


Tôi không nghĩ câu trả lời này có liên quan đến câu hỏi.
Pierre Espenan 17/12/18
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.