Tuple, Swap two items

func mySwap<T>(_ left: inout T, _ right: inout T) {
(left, right) = (right, left)
}

let a: Int = 1
let b: Int = 2
mySwap(a, b)

@escaping

使⽤闭包的⽅式来传递这个参
数是常见⼿段:

func doWork(block: ()->()) {
    block()
}

doWork {
    print("work")
}

这种最简单的形式的闭包其实还默认隐藏了⼀个假设,那就是参数中 block 的内容会在 doWork
返回前就完成。也就是说,对于 block 的调⽤是同步⾏为。如果我们改变⼀下代码,将 block 放
到⼀个 Dispatch 中去,让它在 doWork 返回后被调⽤的话,我们就需要在 block 的类型前加上
@escaping 标记来表明这个闭包是会“逃逸”出该⽅法的:

func doWorkAsync(block: @escaping ()->()) {
    DispatchQueue.main.async {
    block()
}

}
  • capturing value
  • 对于 doWork 参数⾥这样的没有逃逸⾏为的闭包,因为闭包的作⽤域不会超过函数本⾝,所 以我们不需要担⼼在闭包内持有 self 等。
  • ⽽接受 @escaping 的 doWorkAsync 则有所不同。由于需
    要确保闭包内的成员依然有效,如果在闭包内引⽤了 self 及其成员的话,Swift 将强制我们明确
    地写出 self

  • 如果我们不希望在闭包中持有 self ,可以使⽤ [weak
    self] 的⽅式来表达:

func method3() {  
  doWorkAsync { [weak self] _ in  
    print(self?.foo)  
  }  
  foo = "bar"  
}  
method3() // nil

如果在协议或者父类重定义了一个接受@escaping为参数方法,

那么在实现协议和类型或者是这个父类的子类中,对应的方法也必须被声明为@escaping,
否则两个方法会被认为拥有不同的函数签名

protocol P {
    func work(b: @escaping ()->())
}

// 可以编译
class C: P {
    func work(b: @escaping () -> ()) {
        DispatchQueue.main.async {
            print("in C")
            b()
        }
    }
}

// ⽽这样是⽆法编译通过的:
class C1: P {
    func work(b: () -> ()) {
        // ...
    }
}

Overload Operator

overload an operator, that swift has existed operator

struct Vector2D {

var x = 0.0
    var y = 0.0
}

func +(left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(x: left.x + right.x, y: left.y + right.y)
}

let v1 = Vector2D(x: 2.0, y: 3.0)
let v2 = Vector2D(x: 1.0, y: 4.0)
let v4 = v1 + v2
// v4 为 {x 3.0, y 7.0}

overload a new operator, that swift did not contain

  • declare the new operator
precedencegroup DotProductPrecedence {
    associativity: none
    higherThan: MultiplicationPrecedence
}
infix operator +*: DotProductPrecedence

// precedence group - define the priority  
// associativity: - define the 结合律\(Associativity\),  
//     即如果多个同类的操作符顺序出现的计算顺序。  
//     ⽐如常见的加法和减法都是 left ,就是说多个加法同时出现时按照从左往右的顺序计算  
// higherThan: - 运算的优先级,  
//    点积运算是优先于乘法运算的。除了 higherThan ,也⽀持使⽤ lowerThan 来指定优先级低于某个其他组。  
// infix - 表⽰要定义的是⼀个中位操作符,即前后都是输⼊;其他的修饰⼦还包括 prefix 和 postfix
//     let result = v1 +* v2  
// 输出为 14.0

func +* (left: Vector2D, right: Vector2D) -> Double {
    return left.x * right.x + left.y * right.y
}

ISSUE: Swift 的操作符是不能定义在局部域中的,

因为⾄少会希望在能在全局范围使⽤你的操作符,否则操作符也就失去意义了。

另外,来⾃不同 module 的操作符是有可能冲突的。

如果库中的操作符冲突的话,使⽤者是⽆法通过指定库名字来进⾏调⽤的。

func 的参数修饰

  • default passed value in func is let
// default condition
// let can be omitted
func incrementor(variable: let Int) -> Int {
    print(variable)
    return variable
}
  • if we want to modify the passed value

    // after Swift 2.2, we cannot replace let to var directly
    // use another "var" to explicit "let variable",
    // the another "var" can be modified
    func incrementor(variable: Int) -> Int {
      var num = variable
      num += 1
      return num
    }
    
  • if we want to pass the reference

    func incrementor\(variable: inout Int) {
      variable += 1  
    }  
    var luckyNumber = 7  
    incrementor(variable: &luckyNumber)  
    print(luckyNumber)
    // luckyNumber = 8
    
  • 参数的修饰是具有传递限制的,对于跨越层级的调⽤,需要保证同⼀参数的修饰是统⼀的。
    举个例⼦,⽐如我们想扩展⼀下上⾯的⽅法,实现⼀个可以累加任意数字的 +N器 的话,可以写成这样:

    func makeIncrementor(addNumber: Int) -> ((inout Int) -> ()) {  
      func incrementor(inout variable: Int) -> () {
          variable += addNumber
      }
      return incrementor;  
    }
    

literal value expressing 字面量表达

  • 就是指像特定的数字,字符串或者是布尔值这样,能够直截了当地指出⾃⼰的类型 并为变量进⾏赋值的值。⽐如在下⾯:
let aNumber = 3
let aString = "Hello"
let aBool = true
let anArray = [1,2,3]

let aDictionary = ["key1": "value1", "key2": "value2"]
// 其中的 3 , Hello 以及 true 就称为字⾯量。
  • Swift provide several protocols
    ExpressibleByArrayLiteral
    ExpressibleByBooleanLiteral  
    ExpressibleByDictionaryLiteral
    ExpressibleByFloatLiteral
    ExpressibleByNilLiteral  
    ExpressibleByIntegerLiteral  
    ExpressibleByStringLiteral  
    ExpressibleByExtendedGraphemeClusterLiteral  
    ExpressibleByUnicodeScalarLiteral  
    // 所有的字⾯量表达协议都定义了⼀个 typealias 和对应的 init ⽅法
    

Example

protocol ExpressibleByBooleanLiteral {
    typealias BooleanLiteralType
    /// Create an instance initialized to `value`.
    init(booleanLiteral value: BooleanLiteralType)
}

/// in this protocol, BooleanLiteralType 在 Swift 标准库中已经有定义了:

/// The default type for an otherwise-unconstrained boolean literal
typealias BooleanLiteralType = Bool
enum MyBool: Int {
    case myTrue, myFalse
}

extension MyBool: ExpressibleByBooleanLiteral {
    init(booleanLiteral value: Bool) {
        self = value ? .myTrue : .myFalse
    }
}

// we can directly use the  Bool's true and false to init the enum
let myTrue: MyBool = true
let myFalse: MyBool = false
myTrue.rawValue // 0
myFalse.rawValue // 1

Preventing Overrides

  • final: prevent a method, property, or subscript from being overridden. such as final var, final func, final class func, and final subscript).
  • with final, any attempt to override a final method/property/subscript in a subclass is reported as a compile-time error.
  • final class className, any attempt to subclass a final class is reported as a compile-time error.
  • extension can also be marked as final within the extension’s definition.

Identity Operators - only for class

Swift provides two identity operators:

Identical to (===)
Not identical to (!==)

/// check two constants or variables refer to the same single instance:
let tenEighty = VideoMode()
let alsoTenEighty = tenEighty
if tenEighty === alsoTenEighty {
    print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
// Prints "tenEighty and alsoTenEighty refer to the same VideoMode instance."

Note

“identical to” (represented by three equals signs, or ===) does not mean the same thing as “equal to” (represented by two equals signs, or ==):

  • “Identical to” means that two constants or variables of class type refer to exactly the same class instance.
  • “Equal to” means that two instances are considered “equal” or “equivalent” in value, for some appropriate meaning of “equal”, as defined by the type’s designer.

random

最佳实践当然是为创建⼀个 Range 的随机数的⽅法,这样我们就能在之后很容易地复⽤,甚⾄设
计类似与 Randomable 这样的协议了:

func random(in range: Range<Int>) -> Int {
    let count = UInt32(range.endIndex - range.startIndex)
    return Int(arc4random_uniform(count)) + range.startIndex

}

for _ in 0...100 {
    let range = Range<Int>(1...6)
    print(random(in: range))

}

results matching ""

    No results matching ""