几个常用的Swift Extension:防止按钮重复点击、增加友盟页面统计、Dispatch_once Swift实现

//  防止按钮重复点击

//  UIButton+extension.swift

//

//  Created by pilgrim on 2017/2/23.

//  Copyright © 2017 pilgrim. All rights reserved.

//


import UIKit


// 默认间隔时间

fileprivate let defaultDuration =1.0


extension UIButton {



    privatestruct AssociatedKeys {

        staticvar clickDurationTime = "my_clickDurationTime"

        staticvar isIgnoreEvent = "my_isIgnoreEvent"

    }


    // 点击间隔时间

    var clickDurationTime :TimeInterval {

        set {

            objc_setAssociatedObject(self, &AssociatedKeys.clickDurationTime, newValueas TimeInterval, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

        }


        get {


            iflet clickDurationTime = objc_getAssociatedObject(self, &AssociatedKeys.clickDurationTime)as? TimeInterval {

                return clickDurationTime

            }


            return defaultDuration

        }

    }


    // 是否忽视点击事件

    var isIgnoreEvent :Bool {


        set {

            objc_setAssociatedObject(self, &AssociatedKeys.isIgnoreEvent, newValueas Bool, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

        }


        get {


            iflet isIgnoreEvent = objc_getAssociatedObject(self, &AssociatedKeys.isIgnoreEvent)as? Bool {

                return isIgnoreEvent

            }

            

            returnfalse

        }

    }


    overrideopen classfunc initialize() {

        struct Static {

            staticvar token: String = "com.pilgrim.ButtonExtension"

        }


        ifself !== UIButton.self {

            return

        }


        DispatchQueue.once(token: Static.token, block: {


            let originalSelector =#selector(UIButton.sendAction(_:to:for:))

            let swizzledSelector =#selector(UIButton.my_sendAction(action:to:forEvent:))


            let originalMethod = class_getInstanceMethod(self, originalSelector)

            let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)


            // 运行时为类添加我们自己写的my_sendAction(_:to:forEvent:)

            let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))


            if didAddMethod {

                // 如果添加成功,则交换方法

                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))

            } else {

                // 如果添加失败,则交换方法的具体实现

                method_exchangeImplementations(originalMethod, swizzledMethod)

            }

        })

    }


    

// SwizzledMethod

    @objc func my_sendAction(action: Selector, to target: AnyObject?, forEvent event: UIEvent?) {


        if self.isKind(of: UIButton.self) {

            if event?.allTouches?.first?.phase == .began { // 发现原有实现方式,对拍照按钮有影响,迅速TouchDown、TouchUp,TouchUp方法被拦截了。因此在这里忽略touchDown的处理。

                my_sendAction(action: action, to: target, forEvent: event)

            } else {

                clickDurationTime = clickDurationTime == 0 ? defaultDuration : clickDurationTime

                if isIgnoreEvent {

                    return

                } else if clickDurationTime > 0 {

                    isIgnoreEvent = true

                    // 在过了我们设置的duration之后,再将isIgnoreEvent置为false

                    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + clickDurationTime, execute: {

                        self.isIgnoreEvent = false

                    })

                    my_sendAction(action: action, to: target, forEvent: event)

                }

            }

        } else {

            my_sendAction(action: action, to: target, forEvent: event)

        }

    }

}








//  增加友盟页面统计

//  ViewController.swift

//

//  Created by pilgrim on 2017/1/18.

//  Copyright © 2017 pilgrim. All rights reserved.

//


import UIKit


fileprivate var bundleName:String = ""


extension UIViewController {

    

    open override staticfunc initialize() {

        struct Static {

            staticvar token: String = "com.pilgrim.VCExtension"

        }


        // 确保不是子类

        ifself !== UIViewController.self {

            return

        }


        DispatchQueue.once(token: Static.token, block: {

            var bundlePath = Bundle.main.bundlePath

            bundlePath = bundlePath.components(separatedBy: "/").last!

            bundlePath = bundlePath.components(separatedBy: ".").first!

            bundleName = bundlePath


            let originalSelector =#selector(UIViewController.viewWillAppear(_:))

            let swizzledSelector =#selector(newViewWillAppear(animated:))


            let originalSelector1 =#selector(UIViewController.viewWillDisappear(_:))

            let swizzledSelector1 =#selector(newViewWillDisappear(animated:))


            let originalMethod = class_getInstanceMethod(self, originalSelector)

            let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)


            let originalMethod1 = class_getInstanceMethod(self, originalSelector1)

            let swizzledMethod1 = class_getInstanceMethod(self, swizzledSelector1)


            let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))


            let didAddMethod1 = class_addMethod(self, originalSelector1, method_getImplementation(swizzledMethod1), method_getTypeEncoding(swizzledMethod1))


            if didAddMethod {

                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))

            } else {

                method_exchangeImplementations(originalMethod, swizzledMethod);

            }

            if didAddMethod1 {

                class_replaceMethod(self, swizzledSelector1, method_getImplementation(originalMethod1), method_getTypeEncoding(originalMethod1))

            } else {

                method_exchangeImplementations(originalMethod1, swizzledMethod1);

            }

        })

    }


    // MARK: - Method Swizzling


    @objcfunc newViewWillAppear(animated:Bool) {

        ifself isBaseNavigationController ||self isBaseTabBarController || !String(describing:self.self).contains(bundleName) {

        } else {

            MobClick.beginLogPageView(String(describing: self.self))

            print(String(describing: self.self))

        }

        self.newViewWillAppear(animated: animated)

    }


    @objcfunc newViewWillDisappear(animated:Bool) {

        ifself isBaseNavigationController ||self isBaseTabBarController || !String(describing:self.self).contains(bundleName) {

        } else {

            MobClick.endLogPageView(String(describing: self.self))

        }

        self.newViewWillDisappear(animated: animated)

    }

}









//  Swift3 Dispatch_once替代品

//  DispatchQueue+Extension.swift

//

//  Created by pilgrim on 2017/2/23.

//  Copyright © 2017 pilgrim. All rights reserved.

//


import UIKit


public extensionDispatchQueue {


    privatestatic var _onceTracker = [String]()


    /**

     Executes a block of code, associated with a unique token, only once.  The code is thread safe and will

     only execute the code once even in the presence of multithreaded calls.


     - parameter token: A unique reverse DNS style name such as com.vectorform. or a GUID

     - parameter block: Block to execute once

     */

    publicclass func once(token:String, block:()->Void) {

        objc_sync_enter(self)

        defer { objc_sync_exit(self) }


        if _onceTracker.contains(token) {

            return

        }


        _onceTracker.append(token)

        block()

    }

}




猜你喜欢

转载自blog.csdn.net/pilgrim1385/article/details/56668165