当前位置: 首页 > news >正文

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"

相关文章:

  • SpringSecurity6-oauth2-三方gitee授权-授权码模式
  • 鸿蒙 Swiper 组件解析:轮播交互与动画效果全指南
  • 疏通经脉: Bridge 联通逻辑层和渲染层
  • 【python】~实现工具软件:QQ邮件即时、定时发送
  • 算法-基础算法-递归算法(Python)
  • PYTHON从入门到实践10-文件操作与异常
  • 日语学习-日语知识点小记-进阶-JLPT-真题训练-N2阶段(5):2022年12月2023年7月
  • 全新大模型开源,腾讯(int4能打DeepSeek) Vs 谷歌(2GB运行多模态)
  • Gemini-CLI:谷歌开源的命令行AI工具,重新定义开发者工作流
  • MyBatis批量删除
  • HMAC 流程
  • 矩阵的逆 线性代数
  • 代码部落 20250629 CSP-S复赛 模拟赛
  • NV064NV065美光固态闪存NV067NV076
  • java-类和面向对象的一些注意事项
  • 手机射频功放测试学习(二)——手机线性功放的静态电流和小信号(S-Parameter)测试
  • 灵动小组件:个性化手机美化,便捷通知管理
  • JDK自带的HttpClient,替代Apache的更优解?
  • MySQL锁机制全解析
  • 1 Studying《Computer Vision: Algorithms and Applications 2nd Edition》6-10