Swift의 button.addTarget 액션에 매개 변수 첨부


102

buttonClicked 작업에 추가 매개 변수를 전달하려고하는데 Swift에서 구문이 무엇인지 확인할 수 없습니다.

button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)

내 buttonClicked 메서드 :

func buttonClicked(sender:UIButton)
{
    println("hello")
}

누구 아이디어?

당신의 도움을 주셔서 감사합니다.


1
자세한 답변과 모범 사례를 보려면이 링크 를 참조하십시오
시트 al

이 질문은 이미 문제가있는 아키텍처를 설명하고 있기 때문에 좋은 답이 아닙니다. 추가 매개 변수가 필요하지 않습니다. 추가 매개 변수가 필요하다는 것은 아키텍처의 문제입니다.
Sulthan

WARNING TO INTERNET: please check out my answer at the bottom
Mr Heelis

답변:


170

에서 맞춤 매개 변수를 전달할 수 없습니다 addTarget:. 하나의 대안은 tag버튼 의 속성을 설정 하고 태그를 기반으로 작업을 수행하는 것입니다.

button.tag = 5
button.addTarget(self, action: "buttonClicked:", 
    forControlEvents: UIControlEvents.TouchUpInside)

또는 Swift 2.2 이상 :

button.tag = 5
button.addTarget(self,action:#selector(buttonClicked),
    forControlEvents:.TouchUpInside)

이제 tag속성을 기반으로 논리를 수행하십시오.

@objc func buttonClicked(sender:UIButton)
{
    if(sender.tag == 5){

        var abc = "argOne" //Do something for tag 5
    }
    print("hello")
}

4
안녕하세요, tableView에서 indexPath 또는 버튼의 셀을 얻으려면 가능합니까?
NKurapati 2015 년

1
여기에 힌트가 있습니다. 메서드를 비공개로 만들지 마십시오.
OhadM

2
유형 만 Int. 다른 건 없습니다.
scaryguy

2
행과 섹션을 함께 전달하려면 어떻게해야합니까?
Yestay Muratov 2016

3
너무 당신이이 할 수있는 잘못된 방법이다 (118) upvotes (및 계산)에도 불구하고, 알
씨 Heelis

79

buttonClicked 메서드에 추가 매개 변수 (예 : indexPath 또는 urlString)를 보내려면 UIButton을 하위 클래스화할 수 있습니다.

class SubclassedUIButton: UIButton {
    var indexPath: Int?
    var urlString: String?
}

ID 검사기에서 버튼의 클래스를 subclassedUIButton으로 변경해야합니다. 다음을 사용하여 buttonClicked 메서드 내의 매개 변수에 액세스 할 수 있습니다.sender.indexPath 또는 sender.urlString.

참고 : 버튼이 셀 내부에있는 경우 cellForRowAtIndexPath 메서드 (버튼이 생성 된 위치)에서 이러한 추가 매개 변수의 값을 설정할 수 있습니다.


5
이것이 나를 위해 일한 유일한 방법이었습니다. 근데 궁금한데 이거 반 패턴인가요?
scaryguy

1
이것은 내가 생각하는 가장 좋은 방법입니다
두이 호앙

29

모든 사람들이 태그를 사용하는 것에 감사하지만 실제로는 UIButton 클래스를 확장하고 거기에 객체를 추가해야합니다.

태그는이 문제를 해결할 수있는 절망적 인 방법입니다. UIButton을 다음과 같이 확장합니다 (Swift 4에서).

import UIKit
class PassableUIButton: UIButton{
    var params: Dictionary<String, Any>
    override init(frame: CGRect) {
        self.params = [:]
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        self.params = [:]
        super.init(coder: aDecoder)
    }
}

그러면 호출이 호출 될 수 있습니다 (에서 콜론 ":"참고 Selector(("webButtonTouched:"))).

let webButton = PassableUIButton(frame: CGRect(x:310, y:40, width:40, height:40))
webButton.setTitle("Visit",for: .normal)
webButton.addTarget(self, action: #selector(YourViewController.webButtonTouched(_:)), for:.touchUpInside)
webButton.params["myvalue"] = "bob"

그리고 마침내 여기에서 모두 잡으십시오.

@IBAction func webButtonTouched(_ sender: PassableUIButton) {
    print(sender.params["myvalue"] ?? "")
}

이 작업을 한 번 수행하고 프로젝트 전체에서 사용합니다 (자식 클래스에 일반적인 "객체"를 만들고 원하는 것을 버튼에 넣을 수도 있습니다!). 또는 위의 예제를 사용하여 무한한 수의 키 / 문자열 매개 변수를 버튼에 넣습니다. URL, 확인 메시지 방법 등을 포함하는 데 정말 유용합니다.

제쳐두고, SO커뮤니티가 인터넷 주위에 나쁜 습관의 전체 세대가 있다는 것을 깨닫는 것이 중요합니다. 개념object extensions


10

Swift 3.0의 경우 다음을 사용할 수 있습니다.

button.addTarget(self, action: #selector(YourViewController.YourMethodName(_:)), for:.touchUpInside)

func YourMethodName(_ sender : UIButton) {
    print(sender.tag)

}

9

스위프트 4.2

결과:

testButton.on(.touchUpInside) { (sender, event) in
    // You can use any reference initialized before the code block here
    // You can access self by adding [weak self] before (sender, event)
    // You can then either make self strong by using a guard statement or use a optional operator (?)
    print("user did press test button")
}

파일 에서 를 호출하는 완료 처리기에 바인딩 UIButton+Events.swift하는 확장 메서드를 만들었습니다 .UIButtonUIControl.EventEventHandler

import UIKit

fileprivate var bindedEvents: [UIButton:EventBinder] = [:]

fileprivate class EventBinder {

    let event: UIControl.Event
    let button: UIButton
    let handler: UIButton.EventHandler
    let selector: Selector

    required init(
        _ event: UIControl.Event,
        on button: UIButton,
        withHandler handler: @escaping UIButton.EventHandler
    ) {
        self.event = event
        self.button = button
        self.handler = handler
        self.selector = #selector(performEvent(on:ofType:))
        button.addTarget(self, action: self.selector, for: event)
    }

    deinit {
        button.removeTarget(self, action: selector, for: event)
        if let index = bindedEvents.index(forKey: button) {
            bindedEvents.remove(at: index)
        }
    }
}

private extension EventBinder {

    @objc func performEvent(on sender: UIButton, ofType event: UIControl.Event) {
        handler(sender, event)
    }
}

extension UIButton {

    typealias EventHandler = (UIButton, UIControl.Event) -> Void

    func on(_ event: UIControl.Event, handler: @escaping EventHandler) {
        bindedEvents[self] = EventBinder(event, on: self, withHandler: handler)
    }
}

이벤트 바인딩을 위해 사용자 지정 클래스를 사용한 이유는 나중에 버튼이 deintialize 될 때 참조를 삭제할 수 있기 때문입니다. 이렇게하면 메모리 누수가 발생하지 않습니다. UIButton속성이나 deinit메서드 를 구현할 수 없기 때문에 확장 기능 내에서는 불가능 했습니다 .


2

나 같은 버튼 루프가 있다면 이런 식으로 시도해 볼 수 있습니다.

var buttonTags:[Int:String]? // can be [Int:Any]
let myArray = [0:"a",1:"b"]
for (index,value) in myArray {

     let button = // Create a button

     buttonTags?[index] = myArray[index]
     button.tag = index
     button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchDown)

}
@objc func buttonAction(_ sender:UIButton) {

    let myString = buttonTags[sender.tag]

}

2

Swift 4.0 코드 (다시 시작합니다)

호출 된 액션은 객관적인 C 언어로 함수를 내보내기위한 신속한 함수 구문이기 때문에 다음과 같이 표시되어야합니다.

@objc func deleteAction(sender: UIButton) {
}

작동하는 버튼을 만듭니다.

let deleteButton = UIButton(type: .roundedRect)
deleteButton.setTitle("Delete", for: [])
deleteButton.addTarget(self, action: #selector( 
MyController.deleteAction(sender:)), for: .touchUpInside)

공유해 주셔서 감사합니다. 이것은 작동하지만 @objc로 표시하는 것은 직관적이지 않습니다. 그 이유를 설명해 주시겠습니까?
rawbee

@rawbee 이것이 반 직관적이라는 데 동의하십시오. 이 질문에는 더 많은 배경이 있습니다 : stackoverflow.com/questions/44390378/…
Mikrasya

1

Swift 5.0 코드

나는 theButton.tag를 사용하지만 옵션이 많으면 스위치 케이스가 매우 길다.

theButton.addTarget(self, action: #selector(theFunc), for: .touchUpInside) 
theButton.frame.name = "myParameter"

.

@objc func theFunc(sender:UIButton){ 
print(sender.frame.name)
}

0

Swift 2.X 이상

button.addTarget(self,action:#selector(YourControllerName.buttonClicked(_:)),
                         forControlEvents:.TouchUpInside)

0

Swift 3.0 코드

self.timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector:#selector(fetchAutocompletePlaces(timer:)), userInfo:[textView.text], repeats: true)

func fetchAutocompletePlaces(timer : Timer) {

  let keyword = timer.userInfo
}

'userinfo'에서 값을 보내고 함수에서 매개 변수로 사용할 수 있습니다.


0

이것은 더 중요한 의견입니다. 즉시 사용할 수있는 sytanx 참조를 공유합니다. 해킹 솔루션의 경우 다른 답변을 살펴보십시오.

Apple의 문서에 따라 Action Method Definitions 는이 세 가지 중 하나 여야합니다. 다른 것은 허용되지 않습니다.

@IBAction func doSomething()
@IBAction func doSomething(sender: UIButton)
@IBAction func doSomething(sender: UIButton, forEvent event: UIEvent)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.