运行时
-
纯Swift类没有动态性,但在方法、属性前添加dynamic修饰可以获得动态性。
-
继承自NSObject的Swift类,其继承自父类的方法具有动态性,其他自定义方法、属性需要加dynamic修饰才可以获得动态性。
-
若方法的参数、属性类型为Swift特有、无法映射到Objective-C的类型(如Character、Tuple),则此方法、属性无法添加dynamic修饰(会编译错误)
-
Swift类在Objective-C中会有模块前缀
代码示例
extension UIViewController {
public override class func initialize() {
// make sure this isn't a subclass
if self !== UIViewController.self {
return
}
struct Static {
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token) {
//交换viewWillAppear方法
let willAppearSelector = #selector(UIViewController.viewWillAppear(_:))
let sw_willAppearSelector = #selector(UIViewController.sw_viewWillAppear(_:))
let willAppearMethod = class_getInstanceMethod(self, willAppearSelector)
let sw_willAppearMethod = class_getInstanceMethod(self, sw_willAppearSelector)
method_exchangeImplementations(willAppearMethod, sw_willAppearMethod);
}
func sw_viewWillAppear(animated: Bool) {
self.sw_viewWillAppear(animated)
}
}
UTF8
var str = "ABCD☺️"
var byteArray = [UInt8]()
for char in str.utf8{
byteArray += [char]
}
//或者
var buf = [UInt8](str1.utf8)
OptionSet
OptionSet
是一个协议,规定了属性要求rawValue
,这个属性必须遵从BitwiseOperations
协议,比如Int
、UInt8
等。一般创建遵从该协议实例的时候,rawValue
的值为Int
并进行位左移操作。该协议允许以[]
的形式存储多个数值,从而得到新的值,计算方式为按位异或。
Optional
Optional
可以嵌套
Throttle
// Add a searchTask property to your controller
var searchTask: DispatchWorkItem?
// then in your search bar update method
// Cancel previous task if any
self.searchTask?.cancel()
// Replace previous task with a new one
let task = DispatchWorkItem { [weak self] in
self?.sendSearchRequest()
}
self.searchTask = task
// Execute task in 0.75 seconds (if not cancelled !)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.75, execute: task)
func perform(_ aSelector: Selector!)
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(self.reload(_:)), object: searchBar)
perform(#selector(self.reload(_:)), with: searchBar, afterDelay: 0.75)
}
@objc func reload(_ searchBar: UISearchBar) {
}
1. Basic debounce function
func debounce(interval: Int, queue: DispatchQueue, action: @escaping (() -> Void)) -> () -> Void {
var lastFireTime = DispatchTime.now()
let dispatchDelay = DispatchTimeInterval.milliseconds(interval)
return {
lastFireTime = DispatchTime.now()
let dispatchTime: DispatchTime = DispatchTime.now() + dispatchDelay
queue.asyncAfter(deadline: dispatchTime) {
let when: DispatchTime = lastFireTime + dispatchDelay
let now = DispatchTime.now()
if now.rawValue >= when.rawValue {
action()
}
}
}
}
2. Parameterized debounce function
typealias Debounce<T> = (_ : T) -> Void
func debounce<T>(interval: Int, queue: DispatchQueue, action: @escaping Debounce<T>) -> Debounce<T> {
var lastFireTime = DispatchTime.now()
let dispatchDelay = DispatchTimeInterval.milliseconds(interval)
return { param in
lastFireTime = DispatchTime.now()
let dispatchTime: DispatchTime = DispatchTime.now() + dispatchDelay
queue.asyncAfter(deadline: dispatchTime) {
let when: DispatchTime = lastFireTime + dispatchDelay
let now = DispatchTime.now()
if now.rawValue >= when.rawValue {
action(param)
}
}
}
}
3. Example
let debouncedFunction = debounce(interval: 200, queue: DispatchQueue.main, action: { (identifier: String) in
print("called: \(identifier)")
})
DispatchQueue.global(qos: .background).async {
debouncedFunction("1")
usleep(100 * 1000)
debouncedFunction("2")
usleep(100 * 1000)
debouncedFunction("3")
usleep(100 * 1000)
debouncedFunction("4")
usleep(300 * 1000) // waiting a bit longer than the interval
debouncedFunction("5")
usleep(100 * 1000)
debouncedFunction("6")
usleep(100 * 1000)
debouncedFunction("7")
usleep(300 * 1000) // waiting a bit longer than the interval
debouncedFunction("8")
usleep(100 * 1000)
debouncedFunction("9")
usleep(100 * 1000)
debouncedFunction("10")
usleep(100 * 1000)
debouncedFunction("11")
usleep(100 * 1000)
debouncedFunction("12")
}
simulator
#if hasTargetEnvironment(simulator)
...
#else
// FIXME: We need to test this better
...