// 防止按钮重复点击
// 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()
}
}