iOS开发iOS学习首页投稿(暂停使用,暂停投稿)

实现UIButton通过闭包添加事件

2016-11-02  本文已影响471人  _kk_

要实现的效果如下:

btn.addTarget(for: .touchUpInside) { (sender) in
            print("button click!")
        }

很多时候我们的的button点击事件就一行代码,而这一行代码还需要另写一个方法。然后用selector给button。这样:


Snip20161102_1.png

当代码量增大,按钮的点击事件和按钮的定义就分散在代码的不同区域,给后期的代码维护造成不便。为了解决这个问题,我给UIButton扩展了一个用尾随闭包给按钮添加事件的方法。然后代码变成这样:


Snip20161102_2.png
显然要代码集中了,也好好看了!

实现:

想法:给UIButton扩展一个方法带闭包参数的方法,在这个方法中去调用系统的addTraget方法,并把闭包保存起来,在addTraget中Selector对应的方法去执行闭包。

实现步骤:

1、在extension中给UIButton扩展一个带尾随闭包添加事件的方法:

func addTarget(for controlEvents: UIControlEvents,action:@escaping (UIButton)->())
{
}

在该方法中,要做两件事:
一、是给按钮添加响应事件,这个没啥可说的,直接调用系统API。
二、是把闭包保存起来,以便于在响应事件方法中去执行闭包。怎么保存呢,只能通过一个属性保存。extension扩展属性,用到runtime的关联属性方法。直接写一个闭包属性去保存事件闭包:


Snip20161102_3.png

写是没问题,但一运行就会错误,通过实验,发现关联对象不支持基本数据类型,和闭包类型(具体原因我也没弄清楚,等搞清楚再修改过此处)。

鉴于这种情况,定义了一个结构体,在结构体中定义了一个闭包属性。关联一个该结构体类型的对象。问题便迎刃而解。
下面是全部扩展代码:

extension UIButton{
    
    struct AssociatedClosureClass {
        var eventClosure: (UIButton)->()
    }

    private struct AssociatedKeys {
        static var eventClosureObj:AssociatedClosureClass?
    }
    
    private var eventClosureObj: AssociatedClosureClass{
        set{
            objc_setAssociatedObject(self, &AssociatedKeys.eventClosureObj, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            
        }
        get{
            return (objc_getAssociatedObject(self, &AssociatedKeys.eventClosureObj) as? AssociatedClosureClass)!
        }
    }
 
    func addTarget(for controlEvents: UIControlEvents,action:@escaping (UIButton)->()) {
        let eventObj = AssociatedClosureClass(eventClosure: action)
        eventClosureObj = eventObj
        addTarget(self, action: #selector(eventExcuate(_:)), for: controlEvents)
        
    }
    
    @objc private func eventExcuate(_ sender: UIButton){
        eventClosureObj.eventClosure(sender)
    }
}

同理,我们可以写监听通知,timer执行,segement切换的方法扩展。

如果你有更好的想法,或者能解答文中问题,希望看到你的留言。

上一篇 下一篇

猜你喜欢

热点阅读