Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我可以让选择器引用Swift中的闭包吗?_Swift_Closures_Selector - Fatal编程技术网

我可以让选择器引用Swift中的闭包吗?

我可以让选择器引用Swift中的闭包吗?,swift,closures,selector,Swift,Closures,Selector,我想让我的方法的选择器参数引用一个闭包属性,它们都存在于同一个范围内。比如说, func backgroundChange() { self.view.backgroundColor = UIColor.blackColor() self.view.alpha = 0.55 let backToOriginalBackground = { self.view.backgroundColor = UIColor.whiteColor() s

我想让我的方法的
选择器
参数引用一个闭包属性,它们都存在于同一个范围内。比如说,

func backgroundChange() {
    self.view.backgroundColor = UIColor.blackColor()
    self.view.alpha = 0.55

    let backToOriginalBackground = {
        self.view.backgroundColor = UIColor.whiteColor()
        self.view.alpha = 1.0
    }

    NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: #selector(backToOriginalBackground), userInfo: nil, repeats: false)
}
但是,这显示了一个错误:#selector的
参数不能引用属性

当然,我可以定义一个新的、单独的方法,并将闭包的实现转移到它,但我希望对于这样一个小的实现保持它的简洁性

是否可以将闭包设置为
#selector
参数?

否,#selector指的是Objective-C方法

不过,您可以做得更好:向NSTimer添加一个扩展,它允许您创建一个定时计时器,而不是使用目标和选择器,而是使用闭包

否,#选择器指的是Objective-C方法


不过,您可以做得更好:向NSTimer添加一个扩展,它允许您创建一个定时计时器,而不是使用目标和选择器,而是使用闭包

不是直接的,但有些变通方法是可能的。看看下面的例子

/// Target-Action helper.
final class Action: NSObject {

    private let _action: () -> ()

    init(action: @escaping () -> ()) {
        _action = action
        super.init()
    }

    @objc func action() {
        _action()
    }

}

let action1 = Action { print("action1 triggered") }

let button = UIButton()
button.addTarget(action1, action: #selector(action1.action), forControlEvents: .TouchUpInside)

不是直接的,但有些变通办法是可能的。看看下面的例子

/// Target-Action helper.
final class Action: NSObject {

    private let _action: () -> ()

    init(action: @escaping () -> ()) {
        _action = action
        super.init()
    }

    @objc func action() {
        _action()
    }

}

let action1 = Action { print("action1 triggered") }

let button = UIButton()
button.addTarget(action1, action: #selector(action1.action), forControlEvents: .TouchUpInside)

如果将块的作用域更改为类作用域而不是函数,并在其中保留对闭包的引用

您可以使用函数调用该闭包。在课堂上。这样,您就可以将该闭包作为选择器调用

大概是这样的:

class Test: NSObject {
    let backToOriginalBackground = {

    }
    func backgroundChange() {
        NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: #selector(test), userInfo: nil, repeats: false)
    }

    func test() {
        self.backToOriginalBackground()
    }
}

如果将块的作用域更改为类作用域而不是函数,并在其中保留对闭包的引用

您可以使用函数调用该闭包。在课堂上。这样,您就可以将该闭包作为选择器调用

大概是这样的:

class Test: NSObject {
    let backToOriginalBackground = {

    }
    func backgroundChange() {
        NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: #selector(test), userInfo: nil, repeats: false)
    }

    func test() {
        self.backToOriginalBackground()
    }
}

正如@gnasher729所指出的,这是不可能的,因为选择器只是方法的名称,而不是方法本身。在一般情况下,我会在这里使用
dispatch\u
,但在这种特殊情况下,更好的工具IMO是
UIView.animateWithDuration
,因为它正是该函数的功能所在,并且很容易调整转换:

UIView.animateWithDuration(0, delay: 0.5, options: [], animations: {
    self.view.backgroundColor = UIColor.whiteColor()
    self.view.alpha = 1.0
}, completion: nil)

正如@gnasher729所指出的,这是不可能的,因为选择器只是方法的名称,而不是方法本身。在一般情况下,我会在这里使用
dispatch\u
,但在这种特殊情况下,更好的工具IMO是
UIView.animateWithDuration
,因为它正是该函数的功能所在,并且很容易调整转换:

UIView.animateWithDuration(0, delay: 0.5, options: [], animations: {
    self.view.backgroundColor = UIColor.whiteColor()
    self.view.alpha = 1.0
}, completion: nil)

我的解决方案是创建一个类块变量,如:

let completionBlock: () -> () = nil
创建调用此completionBlock的方法:

func completed(){
    self.completionBlock!()
}
我想把选择器放在里面,就像我做的块一样:

func myFunc(){
  self.completionBlock = {//what I want to be done}
  NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: #selector(Myclass.completed), userInfo: nil, repeats: false)
}

我的解决方案是创建一个类块变量,如:

let completionBlock: () -> () = nil
创建调用此completionBlock的方法:

func completed(){
    self.completionBlock!()
}
我想把选择器放在里面,就像我做的块一样:

func myFunc(){
  self.completionBlock = {//what I want to be done}
  NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: #selector(Myclass.completed), userInfo: nil, repeats: false)
}

因此,我对将
选择器
以类似快捷的方式分配给
闭包
的回答类似于已经给出的一些答案,但我想我会分享一个真实的例子,说明我是如何在
UIViewController
扩展中这样做的

fileprivate class BarButtonItem: UIBarButtonItem {
  var actionCallback: ( () -> Void )?
  func buttonAction() {
    actionCallback?()
  }
}

fileprivate extension Selector {
  static let onBarButtonAction = #selector(BarButtonItem.buttonAction)
}

extension UIViewController {
  func createBarButtonItem(title: String, action: @escaping () -> Void ) -> UIBarButtonItem {
    let button = BarButtonItem(title: title, style: .plain, target nil, action: nil)
    button.actionCallback = action
    button.action = .onBarButtonAction
    return button
  }
}

// Example where button is inside a method of a UIViewController 
// and added to the navigationItem of the UINavigationController

let button = createBarButtonItem(title: "Done"){
  print("Do something when done")
}

navigationItem.setLeftbarButtonItems([button], animated: false)

因此,我对将
选择器
以类似快捷的方式分配给
闭包
的回答类似于已经给出的一些答案,但我想我会分享一个真实的例子,说明我是如何在
UIViewController
扩展中这样做的

fileprivate class BarButtonItem: UIBarButtonItem {
  var actionCallback: ( () -> Void )?
  func buttonAction() {
    actionCallback?()
  }
}

fileprivate extension Selector {
  static let onBarButtonAction = #selector(BarButtonItem.buttonAction)
}

extension UIViewController {
  func createBarButtonItem(title: String, action: @escaping () -> Void ) -> UIBarButtonItem {
    let button = BarButtonItem(title: title, style: .plain, target nil, action: nil)
    button.actionCallback = action
    button.action = .onBarButtonAction
    return button
  }
}

// Example where button is inside a method of a UIViewController 
// and added to the navigationItem of the UINavigationController

let button = createBarButtonItem(title: "Done"){
  print("Do something when done")
}

navigationItem.setLeftbarButtonItems([button], animated: false)

现在这是可能的。我为Swift 4中基于块的选择器创建了一个要点

用法:

UIButton().addTarget(选择器,操作:选择器{debugPrint(“我的代码在这里”)},用于:.touchUpInside)`

现在可以了。我为Swift 4中基于块的选择器创建了一个要点

用法:

UIButton().addTarget(选择器,操作:选择器{debugPrint(“我的代码在这里”)},用于:.touchUpInside)`

我至少为UIBarbuttonite尝试了以下方法:

private var actionKey: Void?

extension UIBarButtonItem {

    private var _action: () -> () {
        get {
            return objc_getAssociatedObject(self, &actionKey) as! () -> ()
        }
        set {
            objc_setAssociatedObject(self, &actionKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    convenience init(title: String?, style: UIBarButtonItemStyle, action: @escaping () -> ()) {
        self.init(title: title, style: style, target: nil, action: #selector(pressed))
        self.target = self
        self._action = action
    }

    @objc private func pressed(sender: UIBarButtonItem) {
        _action()
    }

}
然后你可以这样做:

navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Test", style: .plain, action: {
    print("Hello World!")
})

我试过这个,至少是为了维吾尔人:

private var actionKey: Void?

extension UIBarButtonItem {

    private var _action: () -> () {
        get {
            return objc_getAssociatedObject(self, &actionKey) as! () -> ()
        }
        set {
            objc_setAssociatedObject(self, &actionKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    convenience init(title: String?, style: UIBarButtonItemStyle, action: @escaping () -> ()) {
        self.init(title: title, style: style, target: nil, action: #selector(pressed))
        self.target = self
        self._action = action
    }

    @objc private func pressed(sender: UIBarButtonItem) {
        _action()
    }

}
然后你可以这样做:

navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Test", style: .plain, action: {
    print("Hello World!")
})

您可以使用支持UIControl、UIButton、UIRefreshControl、UIGestureRecognitor和UIBarButtonItem的ActionClosurable。

下面展示了一个uibarbuttonite的例子

// UIBarButtonItem
let barButtonItem = UIBarButtonItem(title: "title", style: .plain) { _ in
    print("barButtonItem title")
}

您可以使用支持UIControl、UIButton、UIRefreshControl、UIGestureRecognitor和UIBarButtonItem的ActionClosurable。

下面展示了一个uibarbuttonite的例子

// UIBarButtonItem
let barButtonItem = UIBarButtonItem(title: "title", style: .plain) { _ in
    print("barButtonItem title")
}

@韦雷迪弗的回答很好。这里有一个更新,允许您将其作为函数调用

<代码>导入基础 公共扩展选择器{ ///将闭包包装在“选择器”中。 ///-注意:可作为函数调用。 最后一个类执行:NSObject{ public init(u-perform:@escaping()->Void){ self.perform=perform super.init() } 私有让执行:()->无效 } } //马克:公众 公共扩展选择器。执行{ @objc func callAsFunction(){perform()} 变量选择器:选择器{#选择器(callAsFunction)} }
您需要管理对
选择器的强引用。执行
s。一种方法是对设计用于目标操作的UIKit类进行子类化:

///包装闭包的“UITapgestureRecognitor”。
公共最终类TapGestureRecognitor:UITapGestureRecognitor{
public init(u-perform:@escaping()->Void){
self.perform=.init(执行)
super.init(目标:self.perform,操作:self.perform.selector)
}
public-let-perform:Selector.perform
}

让tapRecognizer=TapGestureRecognizer{print(@werediver的答案非常好。下面是一个更新,允许您将其作为函数调用

<代码>导入基础 公共扩展选择器{ ///将闭包包装在“选择器”中。 ///-注意:可作为函数调用。 最后一个类执行:NSObject{ public init(u-perform:@escaping()->Void){ self.perform=perform super.init() } 私有让执行:()->无效 } } //马克:公众 公共扩展选择器。执行{ @objc func callAsFunction(){perform()} 变量选择器:选择器{#选择器(