目录
- 是否继承 NSObject 内存分析
- optional 可选协议
- dynamic 关键字
- Swift 代码使用 OC 的 KVC/ KVO
- 关联对象(Associated Object)
- 资源管理名 image & font 封装策略
一: 是否继承 NSObject 内存分析
class Person {
var age = 10
var weight: Int = 0
}
内存结构Person对象占用32位,
最前8个字节指向元类, 然后8个字节引用计数相关, 在后8个字节 age , 最后8个字节 weight
class Person: NSObject {
var age = 10
var weight: Int = 0
}
内存结构 Person 对象占用32位, 最前8个字节存放isa指针, 然后8个字节 age , 最后8个字节 weight , 最后8个字节内存对齐
二: 可选协议
1 这些协议只能被类遵守
protocol Runnable1: AnyObject {}
protocol Runnable2: class {} // 这个过期了 AnyObject代替
@objc protocol Runnable3 {} // 除了需要被类swift类遵守, 还将暴露给外部oc类调用
2 可选协议
class SwiftTestController: FTBaseViewController, xxprotocal {
}
@objc protocol xxprotocal {
@objc optional func test()
// 加上 @objc optional 为可选协议, 遵守类可以不实现方法
}
3 或是通过扩展实现协议方法, 打到遵守协议类, 可以不实现协议方法效果
extension xxprotocal {
func test() {
}
}
三: dynamic 关键字
被 @objc dynamic 修饰的内容会具有动态性,比如调用方法会走runtime那一套流程
四: Swift 代码使用 OC 的 KVC/ KVO
1. Swift 代码调用 OC 的 KVC/ KVO
以方法方式调用 KVO
以Block 方式调用 KVO
2. 补充: swift的属性监听器
class Person {
var name : String? {
willSet { // 属性即将改变时进行监听
print("willSet--name----\(name)")
print("willSet--newValue----\(newValue)")
}
didSet { // 属性已经改变时进行监听
print("didSet--name----\(name)")
print("didSet--oldValue----\(oldValue)")
}
}
}
let p = Person()
p.name = "why"
p.name = "yz"
** 打印结果**
willSet--name----nil
willSet--newValue----Optional("why")
didSet--name----Optional("why")
didSet--oldValue----nil
willSet--name----Optional("why")
willSet--newValue----Optional("yz")
didSet--name----Optional("yz")
didSet--oldValue----Optional("why")
五: 关联对象(Associated Object)
在Swift中,class依然可以使用关联对象
默认情况,extension不可以增加存储属性
借助关联对象,可以实现类似extension为class增加存储属性的效果
class Person { }
extension Person {
// 定义全局变量, 只要为了用地址值, Void占一个内存
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
六: 资源管理名
1 图片& 字体封装策略
2 其他策略
更多优秀的思路参考
phttps://github.com/mac-cain13/R.swift
phttps://github.com/SwiftGen/SwiftGen
七: 多线程
- DispatchQueue
// 异步并发队列
let queue1 = DispatchQueue(label: "com.Miss.queue", qos: .default, attributes: .concurrent)
queue1.async(group: group) {
Thread.sleep(forTimeInterval: 3)
print("翻翻书")
}
let queue2 = DispatchQueue(label: "com.Miss.queue", qos: .default, attributes: .concurrent)
queue2.async(group: group) {
print("画画画")
// Thread.sleep(forTimeInterval: 1)
}
let queue3 = DispatchQueue(label: "com.Miss.queue", qos: .default, attributes: .concurrent)
queue3.async(group: group) {
print("看看景")
Thread.sleep(forTimeInterval: 2)
}
group.notify(queue: DispatchQueue.main) {
print("收拾下")
}
/**
画画画
看看景
翻翻书
收拾下
**/
多线程 -- 补充DispatchQueue & DispatchWorkItem
- 延迟执行 asyncAfter
let item = DispatchWorkItem {
print("来来来\(Thread.current)")
}
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3, execute: item)
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 3) {
print("来来来\(Thread.current)")
}
// 来来来<_NSMainThread: 0x6000035c86c0>{number = 1, name = main}
// 来来来<NSThread: 0x600003549b40>{number = 7, name = (null)}
- 初始化一次 单例可以用
dispatch_once 在Swift中已被废弃
可以创建静态全局变量/ 变量 实现 static
默认自带 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.initTask1 // 初始一次
let _ = initTask2 // 初始画一次
}
- 多线程 加锁
4.1 信号量加锁
- 多线程 加锁
// 封装一个缓存库
class Cache {
private static var data = [String: Any]()
private static var lock = DispatchSemaphore(value: 2) // 最多两条线程可以访问
static func set(_ key: String, _ value: Any) {
lock.wait()
defer { lock.signal() } // defer: 方法退出前执行
data[key] = value
}
}
4.2 Foundation NSLock
private static var lock = NSLock()
static func set(_ key: String, _ value: Any) {
lock.lock()
defer {lock.unLock()}
}
4.3 递归锁
方法中包含递归调用时候使用
rivate static var lock = NSRecursiveLock()
static func set(_ key: String, _ value: Any) {
lock.lock()
defer { lock.unlock()}
}
八: Array 常用Api
- 遍历数组
let array = [1,2,3,4]
// func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
// 返回数组, 遍历数组, 通过item返回每个元素, 表达式返回每个新元素, 同时生成一个新数组
let array1 = array.map { (item: Int) -> Int in
item * 2 // { $0 * 2 }
}
print(array1) // [2, 4, 6, 8]
let array11 = array.map { item in
"\(item)"
}
print(array11) // ["1", "2", "3", "4"]
- 过滤数组
// func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]
// 返回数组, 通过表达式返回Bool值, 过滤掉返回false的值
let array2 = array.filter { item in
item / 2 == 0 // { $0 / 2 }
}
print(array2) // [1]
- 遍历带参数保存结果
// func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
// 返回值, 初始值, 闭包返回的Result值三者相同,
// 表达式计算结果通过 partialResult 保存
let array3 = array.reduce(1) { (partialResult, Element) -> Int in
return partialResult + Element // { $0 + $1 }
}
print(array3) // 10
- 相关
// 遍历 字符串数组 转Int数组
let arr = ["123", "test", "jack", "-30"]
var arr2 = arr.map { Int($0) }
print(arr2) // [Optional(123), nil, nil, Optional(-30)]
// 缩进数组
var arr3 = arr.compactMap { Int($0) }
print(arr3) // [123, -30]
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: $
// 数组遵守了equalable协议
let array = [1] + [1,2]
print(array) // [1, 1, 2]
九: Optional的map和flatMap
- 可选项.map, 可选项 .flatMap
var num1: Int? = 10
var num2 = num1.map { (num) -> Int in
num * 2
} // Optional(20)
var num3: Int? = nil
var num4 = num3.map { $0 * 2 } // nil
// 有值返回可选类型, 否则返回nil
var num1: Int? = 10
var num2 = num1.map { Optional.some($0 * 2) } // Optional(Optional(20))
var num3 = num1.flatMap { Optional.some($0 * 2) } // Optional(20)
// flatMap发现是可选类型, 就不在加可选了
var num1: Int? = 10
var num2 = (num1 != nil) ? (num1! + 10) : nil
var num3 = num1.map { $0 + 10 }
// 省去了判断可选是否为nil 的操作
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 date3 = str.flatMap { string in
return fmt.date(from: string)
}
var date2 = str.flatMap(fmt.date) // 参数是闭包 fmt.date是函数, so...
// 日期格式设置可选时间
var score: Int? = 98
// old
var str1 = score != nil ? "socre is \(score!)" : "No score"
// new
var str2 = score.map { "score is \($0)" } ?? "No score"
网友评论