swift-19-从OC到Swift、函数式编程
一、定义只能被class继承的协议
protocol Runnable1: AnyObject {}protocol Runnable2: class {} @objc protocol Runnable3 {}
被 @objc 修饰的协议,还可以暴露给OC去遵守实现
二、可选协议
可以通过 @objc 定义可选协议这种协议只能被 class 遵守和extension
protocol Runnable {
func run1()
func run2()
func run3()
}第二种
@objc protocol Runnable {
func run1()
@objc optional func run2()
func run3()
}class Dog: Runnable {
func run3() { print("Dog run3") }
func run1() { print("Dog run1") }
}
var d = Dog()
d.run1() // Dog run1
d.run3() // Dog run3第二种
extension Runnable {
func run1(){}
}
三、dynamic
被 @objc dynamic 修饰的内容会具有动态性,比如调用方法会走runtime那一套流程,不加走虚表的调用方法的流程
四、 KVC\KVO
class Observer: NSObject {
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
print("observeValue", change?[.newKey] as Any)
}
}class Person: NSObject {
@objc dynamic var age: Int = 0
var observer: Observer = Observer()
override init() {
super.init()
self.addObserver(observer,
forKeyPath: "age",
options: .new,
context: nil)
}
deinit {
self.removeObserver(observer,
forKeyPath: "age")
}
}
var p = Person()
// observeValue Optional(20)
p.age = 20
// observeValue Optional(25)
p.setValue(25, forKey: "age")
4.1 block方式的KVO
class Person: NSObject {
@objc dynamic var age: Int = 0
var observation: NSKeyValueObservation?
override init() {
super.init()
observation = observe(\Person.age, options: .new) {
(person, change) in
print(change.newValue as Any)
}
}
}
var p = Person()
// Optional(20)
p.age = 20
// Optional(25)
p.setValue(25, forKey: "age")
五、关联对象(Associated Object)
在Swift中,class依然可以使用关联对象
默认情况 ,extension不可以增加存储属性
借助关联对象 ,可以实现类似extension为class增加存储属性的效果
class Person {}
extension Person {
private static var AGE_KEY: Void?
var age: Int {
get {
(objc_getAssociatedObject(self, &Self.AGE_KEY) as? Int) ?? 0
}
set {
objc_setAssociatedObject(self,
&Self.AGE_KEY, newValue,
.OBJC_ASSOCIATION_ASSIGN)
}
}
}var p = Person() print(p.age) // 0 p.age = 10
print(p.age) // 10
六、资源名管理
第一种
let img = UIImage(named: "logo")let btn = UIButton(type: .custom) btn.setTitle("添加", for: .normal)
performSegue(withIdentifier: "login_main", sender: self)enum R {
enum string: String { case add = "添加"
}
enum image: String {
case logo
}
enum segue: String {
case login_main
}
}let img = UIImage(R.image.logo)let btn = UIButton(type: .custom)
btn.setTitle(R.string.add, for: .normal)performSegue(withIdentifier: R.segue.login_main, sender: self)这种做法实际上是参考了Android的资源名管理方式
第二种
extension UIImage {
convenience init?(_ name: R.image) {
self.init(named: name.rawValue)
}
}extension UIViewController {
func performSegue(withIdentifier identifier: R.segue, sender: Any?) {
performSegue(withIdentifier: identifier.rawValue, sender: sender)
}
}extension UIButton {
func setTitle(_ title: R.string, for state: UIControl.State) {
setTitle(title.rawValue, for: state)
}
}
第三 资源名管理的其他思路
let img = UIImage(named: "logo")let font = UIFont(name: "Arial", size: 14)let img = R.image.logolet font = R.font.arial(14)enum R {
enum image {
static var logo = UIImage(named: "logo")
}
enum font {
static func arial(_ size: CGFloat) -> UIFont? {
UIFont(name: "Arial", size: size)
}
}
}更多优秀的思路参考https://github.com/mac-cain13/R.swift https://github.com/SwiftGen/SwiftGen
七、多线程开发 – 异步
public typealias Task = () -> Voidpublic static func async(_ task: @escaping Task) {
_async(task)
}public static func async(_ task: @escaping Task,
_ mainTask: @escaping Task) {
_async(task, mainTask)
}private static func _async(_ task: @escaping Task,
_ mainTask: Task? = nil) {
let item = DispatchWorkItem(block: task)
DispatchQueue.global().async(execute: item)
if let main = mainTask {
item.notify(queue: DispatchQueue.main, execute: main)
}
}
八、多线程开发 – 延迟
@discardableResult
public static func asyncDelay(_ seconds: Double,
_ task: @escaping Task) -> DispatchWorkItem {
return _asyncDelay(seconds, task)
}@discardableResult
public static func asyncDelay(_ seconds: Double,
_ task: @escaping Task,
_ mainTask: @escaping Task) -> DispatchWorkItem {
return _asyncDelay(seconds, task, mainTask)
}
private static func _asyncDelay(_ seconds: Double,
_ task: @escaping Task,
_ mainTask: Task? = nil) -> DispatchWorkItem {
let item = DispatchWorkItem(block: task)
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + seconds,
execute: item)
if let main = mainTask {
item.notify(queue: DispatchQueue.main, execute: main)
}
return item }
九、多线程开发 – once
dispatch_once在Swift中已被废弃 ,取而代之
可以用类型属性或者全局变量\常量
默认自带 lazy + dispatch_once 效果
fileprivate let initTask2: Void = {
print("initTask2---------")
}()class ViewController: UIViewController {
static let initTask1: Void = {
print("initTask1---------")
}()override func viewDidLoad() {
super.viewDidLoad()let _ = Self.initTask1let _ = initTask2
}
}
十、多线程开发 – 加锁
gcd信号量
class Cache {
private static var data = [String: Any]()
private static var lock = DispatchSemaphore(value: 1)
static func set(_ key: String, _ value: Any) {
lock.wait()
defer { lock.signal() }data [key] = value
}
}Foundation
private static var lock = NSLock()
static func set(_ key: String, _ value: Any) {
lock.lock()
defer { lock.unlock() }
}private static var lock = NSRecursiveLock()
static func set(_ key: String, _ value: Any) {
lock.lock()
defer { lock.unlock() }
}
十一、Array的常见操作
var arr = [1, 2, 3, 4]
// [2, 4, 6, 8] 用来映射成其他对应的值
var arr2 = arr.map { $0 * 2 }
// [2, 4] 过滤
var arr3 = arr.filter { $0 % 2 == 0 }
// 10 有关联的,下次遍列会使用上次遍列的值 在这里是将数组里面的元素加起来
var arr4 = arr.reduce(0) { $0 + $1 }
// 10
var arr5 = arr.reduce(0, +)
reduce
map
func double(_ i: Int) -> Int { i * 2 }
var arr = [1, 2, 3, 4]
// [2, 4, 6, 8]
print(arr.map(double))
map 和 flatMap 的区别
var arr = [1, 2, 3]
// [[1], [2, 2], [3, 3, 3]]
var arr2 = arr.map { Array.init(repeating: $0, count: $0) }
// [1, 2, 2, 3, 3, 3] 铺平成一维 我把数组元素给你,一定要返回一个数组元素
var arr3 = arr.flatMap { Array.init(repeating: $0, count: $0) }
compactMap和map
var arr = ["123", "test", "jack", "-30"]
// [Optional(123), nil, nil, Optional(-30)]
var arr2 = arr.map { Int($0) }
// [123, -30]
var arr3 = arr.compactMap { Int($0) }
使用reduce实现map、 filter的功能
// 使用reduce实现map、 filter的功能
var arr = [1, 2, 3, 4]
// [2, 4, 6, 8]
print(arr.map { $0 * 2 })
print(arr.reduce([]) { $0 + [$1 * 2] })// [2, 4]
print(arr.filter { $0 % 2 == 0 })
print(arr.reduce([]) { $1 % 2 == 0 ? $0 + [$1] : $0 })
十二、lazy的优化
let arr = [1, 2, 3]
let result = arr.lazy.map {
(i: Int) -> Int in
print("mapping \(i)")
return i * 2
}
print("begin-----")
print("mapped", result [0])
print("mapped", result [1])
print("mapped", result [2])
print("end----")begin----- mapping 1 mapped 2 mapping 2 mapped 4 mapping 3 mapped 6 end----
十三、Optional的map和flatMap
var num1: Int? = 10
// Optional(20)
var num2 = num1.map { $0 * 2 }var num3: Int? = nil
// nil
var num4 = num3.map { $0 * 2 }var num1: Int? = 10
// Optional(Optional(20))
var num2 = num1.map { Optional.some($0 * 2) }
// Optional(20)
var num3 = num1.flatMap { Optional.some($0 * 2) }var num1: Int? = 10
var num2 = (num1 != nil) ? (num1 ! + 10) : nil
var num3 = num1.map { $0 + 10 }
// num2、 num3是等价的var fmt = DateFormatter()
fmt.dateFormat = "yyyy-MM-dd" var str: String? = "2011-09-10"
// old
var date1 = str != nil ? fmt.date(from: str!) : nil
// new
var date2 = str.flatMap(fmt.date)var score: Int? = 98
// old
var str1 = score != nil ? "soc re is \(score !)" : "No score"
// new
var str2 = score.map { "score is \($0)" } ?? "No score"