簡體   English   中英

將 swift 中的閉包作為參數傳遞給 function 中的選擇器使用

[英]Passing closure in swift as parameter to be used by selector in function

我正在嘗試創建一個通用按鈕創建 function,我將一個閉包傳遞到其中,該閉包表示單擊按鈕后產生的操作。 我的代碼如下。 但是,我收到以下錯誤:#selector 的參數無法引用屬性。 有什么解決方法的建議嗎? 我不想編寫單獨的函數,除了目標操作之外,其他所有內容都相同。

 func myButton(textColor tColor:UIColor , title:String, 
                 _ buttonFcn: (UIButton) -> Void,   
                 titleSize:CGFloat=30) -> UIButton {
    let newButton = UIButton(type: .System)
    let bgColor = UIColor(red:204/255, green:204/255, blue:204/255, alpha:1.0)
    newButton.backgroundColor = bgColor

    newButton.setTitle(title, forState: .Normal)
    newButton.setTitleColor(tColor, forState: .Normal)

    newButton.titleLabel?.font = newButton.titleLabel?.font.fontWithSize(titleSize)


    newButton.addTarget(self,  action:#selector(buttonFcn),
                        forControlEvents: 
                           UIControlEvents.TouchUpInside)

    return newButton
}

問題在於目標動作機制是一種Objective-C機制,因此基於動作選擇器是一種對象 方法的概念來進行判斷。 因此,您需要具有一些基於NSObject的對象 ,該對象具有將此功能用作方法 ,然后可以用作目標。

因此,如果目標和操作在每種情況下都不同,那么您需要傳遞的是對目標的引用以及選擇器字符串 Swift會對此之以鼻,但是,如果您知道如何正確形成選擇器字符串,那么您當然可以擺脫它; 您將無法使用#selector語法,因此,如果輸入格式不正確,可能會導致崩潰。 但這是我們在過去的Objective-C時代一直做的事情,因此,如果這是您的目標,那就繼續吧。

完全人為但可行的示例:

func buttonMaker(target:NSObject, selectorString:String) -> UIButton {
    let b = UIButton(type:.system)
    b.setTitle("Testing", for: .normal)
    b.addTarget(target, action: Selector(selectorString), for: .touchUpInside)
    b.sizeToFit()
    return b
}

這是從視圖控制器調用它的方法:

func doButton(_ sender:Any) {
    print("ha!")
}

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    let b = buttonMaker(target:self, selectorString:"doButton:")
    b.frame.origin = CGPoint(x:100, y:100)
    self.view.addSubview(b)
}

而且當我們點擊按鈕時,我們不會崩潰(而是打印“ ha”),因為我知道如何正確制作選擇器字符串。 但是,正如您所看到的,要實現此目的,我必須完全放棄使用#selector ,因此安全性不在考慮之列。 如果我沒有正確輸入選擇器字符串(例如,如果我拼寫錯誤或省略了冒號),我們將在按鈕點擊時崩潰,就像我們在Swift #selector和Objective-C之前一直都一樣@selector被發明了。

如果您的部署目標是 iOS 14 或更高版本,您可以使用addAction方法而不是addTarget addAction方法允許您使用閉包而不是選擇器:

func myButton(
    textColor: UIColor,
    title: String,
    titleSize: CGFloat = 30,
    _ handler: @escaping (UIButton) -> Void
) -> UIButton {
    let button = UIButton(type: .system)
    button.backgroundColor = UIColor(red: 204/255, green: 204/255, blue: 204/255, alpha: 1.0)
    button.setTitle(title, for: .normal)
    button.setTitleColor(textColor, for: .normal)
    button.titleLabel?.font = button.titleLabel?.font.withSize(titleSize)

    let action = UIAction { action in
        guard let button = action.sender as? UIButton else { return }
        handler(button)
    }
    button.addAction(action, for: .touchUpInside)

    return button
}

iOS 14於2020-09-16發布,支持iPhone 6S及之后的設備。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM