Swift 语法

Apr 25, 2016


运行时

  • 纯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协议,比如IntUInt8等。一般创建遵从该协议实例的时候,rawValue的值为Int并进行位左移操作。该协议允许以[]的形式存储多个数值,从而得到新的值,计算方式为按位异或。

Optional

Optional可以嵌套

Swift 烧脑体操(一) - Optional 的嵌套

Throttle

DispatchWorkItem

// 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) {
}

Debounce

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
 ...