Swift好文收藏

Swift 小札

2018-11-28  本文已影响15人  纯情_小火鸡

associatedtype

associatedtype用于在protocol中代指一个确定类型并要求该类型实现指定方法

protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}

struct IntStack: Container {
    // original IntStack implementation
    var items = [Int]()
    mutating func push(_ item: Int) {
        items.append(item)
    }
    mutating func pop() -> Int {
        return items.removeLast()
    }
    // conformance to the Container protocol
    typealias Item = Int
    mutating func append(_ item: Int) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Int {
        return items[i]
    }
}

where

where语句可以用来设置约束条件、限制类型,让代码更加简洁、易读。

  1. 可以使用 where 关键词在 switch、for in 语句上做些条件限制。

    for score in scores where score >= 90 {}
    
  2. 在 do catch 里面使用。

    enum ExceptionError:Error{
        case httpCode(Int)
    }
     
    func throwError() throws {
        throw ExceptionError.httpCode(500)
    }
     
    do{
        try throwError()
    }catch ExceptionError.httpCode(let httpCode) where httpCode >= 500{
        print("server error")
    }catch {
        print("other error")
    }
    
    1. 与协议结合来设置限制类型。

    2. 在 associatedtype 后面声明的类型后追加 where 约束语句。

      protocol Sequence {
          associatedtype Element where Self.Element == Self.Iterator.Element
          //它限定了 Sequence 中 Element 这个类型必须和 Iterator.Element 的类型一致
      }
      

Sequence

序列的一切功能都是建立在 Sequence 协议之上,定义了map,filter,forEach,dropFirst,flatMap等方法。

序列有两个特性:1. 它的容量可以有限也可无限,2. 只可以迭代 (iterate) 一次。

protocol Sequence {
    associatedtype Iterator: IteratorProtocol
    func makeIterator() -> Iterator
}

序列协议有两个组成部分。一个是一个关联类型 (associated type),也就是这个 Iterator(迭代器)。这个关联类型必须要遵循 IteratorProtocol 协议;另一个组成部分是一个函数,它能够为我们构建 Iterator,这个函数返回的类型必须与我们声明的 Iterator 类型相同。

IteratorProtocol 协议看起来与 Sequence 协议类似。它有一个关联类型 Element,这个 Element 就是迭代器所声明的类型,或者说是需要迭代的类型;此外它还有一个名为 next 的函数,它会返回序列的下一个元素并对迭代器本身进行修改 (mutate)。

protocol IteratorProtcol {
    associatedtype Element
    mutating func next() -> Element?
}

indirection

用来声明递归枚举,告诉编译器插入必要的间接层。

indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

func evaluate(_ expression: ArithmeticExpression) -> Int {
    switch expression {
    case let .number(value):
        return value
    case let .addition(left, right):
        return evaluate(left) + evaluate(right)
    case let .multiplication(left, right):
        return evaluate(left) * evaluate(right)
    }
}

@objcMembers

如果只想公开一个方法或属性,可以使用@objc属性标记该方法。然而,如果你想让类中的所有方法都暴露给Objective-C,可以使用一个快捷方式:@objcMembers关键字,@objc 相对于@objcMembers 而言,可能会增大包的编译大小。

@objcMembers class MyController: UIViewController {
    //login()方法将自动暴露给Objective-C,就像它被标记为@objc一样,因为它所在的整个类被标记为@objcMembers
    func login() {

    }
}

.Type

.Type 表示的是某个类型的元类型,元类型就是类型的类型。而在 Swift 中,除了 classstructenum 这三个类型外,我们还可以定义 protocol。对于 protocol 来说,有时候我们也会想取得接口的元类型。这时我们可以在某个 protocol 的名字后面使用 .Protocol 来获取,使用的方法和 .Type 是类似的。

The metatype of a class, structure, or enumeration type is the name of that type followed by .Type. The metatype of a protocol type—not the concrete type that conforms to the protocol at runtime—is the name of that protocol followed by .Protocol. For example, the metatype of the class type SomeClass is SomeClass.Type and the metatype of the protocol SomeProtocol is SomeProtocol.Protocol.

.self

获得元类型的值。当我们访问静态变量或静态函数的时候其实也是通过元类型访问的,只是 Xcode 帮我们省略了 .self。

You can use the postfix self expression to access a type as a value. For example, SomeClass.self returns SomeClass itself, not an instance of SomeClass. And SomeProtocol.self returns SomeProtocol itself, not an instance of a type that conforms to SomeProtocol at runtime. You can use a type(of:) expression with an instance of a type to access that instance’s dynamic, runtime type as a value, as the following example shows:

Easy example

struct Something {
    var x = 5
}

let a = Something()
type(of:a) == Something.self // true

Hard example

class BaseClass {
    class func printClassName() {
        print("BaseClass")
    }
}
class SubClass: BaseClass {
    override class func printClassName() {
        print("SubClass")
    }
}

let someInstance: BaseClass = SubClass()
/*                      |                |
                    compileTime       Runtime
                        |                | 
To extract, use:       .self          type(of)

  The compile-time type of someInstance is BaseClass,
  and the runtime type of someInstance is SubClass */

type(of: someInstance) == SubClass.self // TRUE
type(of: someInstance) == BaseClass.self // FALSE





Enumerations

关于序列和集合需要知道的二三事

上一篇下一篇

猜你喜欢

热点阅读