Swift进阶学习笔记

设计原则

不允许忽略错误的设计原则

不断的将模板代码和功能代码分离,实现高可重用性

contains使用

检查一个序列中的所有元素是否全部都满足某个条件, 封装一个更具有描述性名字的新函数

extension Sequence {
  public func all(matching predicate: (Element) -> Bool) -> Bool {
  // 对于 个条件,如果没有元素 满 它的话,那意味着所有元素都满 它:
  return !contains { !predicate($0) } }
}
let evenNums = nums.filter { $0 % 2 == 0 } // [2, 4, 6, 8, 10] 
evenNums.all { $0 % 2 == 0 } // true
复制代码

flatMap使用

实现原理

extension Array {
  func flatMap<T>(_ transform: (Element) -> [T]) -> [T] {
    var result: [T] = []
    for x in self {
      // map的实现区别是append(_:)
      result.append(contentsOf: transform(x)) 
    }
    return result 
  }
}
复制代码

forEach使用

在一个 view controller 里你想把一个数组中的视图都加到当前 view 上的话,只需要写 theViews.forEach(view.addSubview) 就足够了 因为return会造成行为不太明确,建议大多数其他情况不要用forEach

切片ArraySlice

切片类型只是数组的一种表示方式,它背后的数据仍 然是原来的数组,只不过是用切片的方式来进行表示。这意味着原来的数组并不需要被复制。 ArraySlice 具有的方法和 Array 上定义的方法是一致的,因此你可以把它当做数组来进行处理。 如果你需要将切片转换为数组的话,你可以通过把它传递给 Array 的构建方法来完成 注: 切片只是数组的另一种表示形式,实际数据还是指向原来的存储位置,这样的目的是保持操作的高效,不要每次都复制一次数组,和写时复制是同样的原理

有用的字典方法

字典合并merge(_:uniquingKeysWith:),它接受两个参数,第一个是要进行合并的键值对,第二个是定义如何合并相同键的两个值的函数。我们可以使用这个方法将一个字典合并 至另一个字典中去,如下例所示:

var settings = defaultSettings
let overriddenSettings: [String:Setting] = ["Name": .text("Jane's iPhone")] 
settings.merge(overriddenSettings, uniquingKeysWith: { $1 })
settings
// ["Name": Setting.text("Jane\'s iPhone"), "Airplane Mode": Setting.bool(false)]
复制代码

{ $1 } 表示相同key的时候取第二个,也可以自定义逻辑返回

mapValues方法能够保持字典结构,只对其中的值进行映射

let settingsAsStrings = settings.mapValues { setting -> String in 
  switch setting {
    case .text(let text): return text
    case .int(let number): return String(number)
    case .bool(let value): return String(value)
  } 
}
settingsAsStrings // ["Name": "Jane\'s iPhone", "Airplane Mode": "false"]
复制代码

可选值

a = 10 和 a? = 10 的细微不同。前一种写法无条件地将一个新值赋给变量,而后一种写 法只在 a 的值在赋值发生前不是 nil 的时候才生效。

var a:Int?=5 
a?=10
a // Optional(10)
var b: Int? = nil
b?=10
b // nil
复制代码

多个可选值 let m = i ?? j ?? k ?? 0

可选值map的使用

// before
var firstCharAsString: String? = nil 
if let char = characters.first {
  firstCharAsString = String(char) 
}
// after
let firstChar = characters.first.map { String($0) } // Optional("a")
复制代码

可选值flatMap的使用 fatMap 可以把结果展平为单个可选值Int??, 而不是原来的结果Int?? 不仅可以展平数组,还可以展平可选值

// before
if let a = stringNumbers.first, let b = Int(a) { 
  print(b)
} //1
// after
let y = stringNumbers.first.flatMap { Int($0) } // Optional(1)
复制代码

结构体

写时复制(高效方式) 为了提供高效的写时复制特性,我们需要知道一个对象是否是 唯一的。如果它是唯一引用,那么我们就可以直接原地修改对象。否则,我们需要在修改前创 建对象的复制。在 Swift 中,我们可以使用 isKnownUniquelyReferenced 函数来检查某个引 用只有一个持有者。如果你将一个 Swift 类的实例传递给这个函数,并且没有其他变量强引用 这个对象的话,函数将返回 true。

编码和解码

编码器: 将类转化成json

解码器: 将json转换类

函数

闭包: 一个函数和它所捕获的变量环境组合起来被称为闭包。

闭包表达式: 函数可以使用 { } 来声明为闭包表达式

键路径

属性相互绑定

extension NSObjectProtocol where Self: NSObject {
    func observe<A, Other>(_ keyPath: KeyPath<Self, A>,
                           writeTo other: Other,
                           _ otherKeyPath: ReferenceWritableKeyPath<Other, A>)
        -> NSKeyValueObservation where A: Equatable, Other: NSObjectProtocol
    {
        return observe(keyPath, options: .new) { _, change in
            guard let newValue = change.newValue, other[keyPath: otherKeyPath] != newValue else {
                return // prevent endless feedback loop
            }
            other[keyPath: otherKeyPath] = newValue }
        }
}

extension NSObjectProtocol where Self: NSObject {
    func bind<A, Other>(_ keyPath: ReferenceWritableKeyPath<Self,A>,
                        to other: Other,
                        _ otherKeyPath: ReferenceWritableKeyPath<Other,A>)
        -> (NSKeyValueObservation, NSKeyValueObservation) where A: Equatable, Other: NSObject
    {
        let one = observe(keyPath, writeTo: other, otherKeyPath)
        let two = other.observe(otherKeyPath, writeTo: self, keyPath)
        return (one,two)
    }
}

final class Sample: NSObject {
  @objc dynamic var name: String = ""
}
class MyObj: NSObject {
  @objc dynamic var test: String = ""
}
let sample = Sample()
let other = MyObj()
let observation = sample.bind(\Sample.name, to: other, \.test) sample.name = "NEW"
other.test // NEW
other.test = "HI"
sample.name // HI
复制代码

自动闭包

@escaping: 稍后调用的闭包叫做逃逸闭包

@autoclosure: 告诉编译器它应该将某个参数用闭包表达式包装起来,不需要将参数封装到闭包中

if and(!evens.isEmpty, { evens[0] > 10 }) { 
  //执⾏行行操作
}
if and(!evens.isEmpty, evens[0] > 10) { // @autoclosure修饰
  //执⾏行行操作
}
复制代码

错误处理

rethrows: 告诉编译器,这个函数只会在它的参数函数抛出错误的时候抛 出错误。对那些向函数中传递的是不会抛出错误的函数的调用,编译器可以免除我们一定要使用 try 来进行调用的要求

extension Sequence {
  func all(matching predicate: (Element) throws -> Bool) rethrows -> Bool {
    for element in self {
      guard try predicate(element) else { return false } 
    }
      return true
  } 
}
复制代码

原生并行特性还没有被添加到Swift

可以使用PromiseKit来暂时代替使用

协议

带有关联类型的协议

public protocol IteratorProtocol {
  associatedtype Element
  public mutating func next() -> Element?
}
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值