• Swift3.0 泛型<T> 2017-05-25 17:58:44
    泛型能够让开发者编写自定义需求已经任意类型的灵活可用的的函数和类型。能够让我们避免重复的代码。用一种清晰和抽象的方式来表达代码的意图。 1.泛型解决的问题 下面是一个非泛型的例子 func swapTwoIntValue(in...
    泛型能够让开发者编写自定义需求已经任意类型的灵活可用的的函数和类型。能够让我们避免重复的代码。用一种清晰和抽象的方式来表达代码的意图。

    1.泛型解决的问题

    下面是一个非泛型的例子
    func swapTwoIntValue(a: inout Int, b: inout Int){
        let tempValue = a
        a = b
        b = tempValue
    }
    这个函数用来交换两个整形的数值
    var a = 1
    var b = 2
    swapTwoIntValue(a: &a, b: &b)
    print(a, b)//2,1
    对于这个例子,假如我们想交换两个Double类型、或者是其他类型的值,就需要针对每个类型写不同的方法,只是参数类型不同。为了解决这个问题,Swift提供了泛型,帮助我们来解决这个问题。
    注意:Swift是安全的语言,不允许两个不同类型互换值

    2.泛型函数

    下面是一个泛型的函数
    func swapTwoValue<T>(a: inout T, b: inout T){
        let tempValue = a
        a = b
        b = tempValue
    }

    这个函数主体、功能跟上面的例子类似,用来交换两个同样类型的值,但是这个函数用 T 占位符来代替实际的类型。并没有指定具体的类型,但是传入的a ,b 必须是同一类型T。在调用这个函数的时候才能指定 T 是那种具体的类型。还有函数名后跟的那个 <T> 是函数定义的一个占位类型名,并不会查找T的具体类型
    swapTwoValue(&oneInt, b: &twoInt)
    print("oneInt:\(oneInt),twoInt:\(twoInt)") // oneInt:3,twoInt:4
    
    var oneStr = "hello"
    var twoStr = "world"
    
    swapTwoValue(&oneStr, b: &twoStr)
    print("oneStr:\(oneStr),twoStr:\(twoStr)")// oneStr:world,twoStr:hello
    
    var oneDouble = 10.01
    var twoDouble = 20.02
    swapTwoValue(&oneDouble, b: &twoDouble)
    print("oneDouble:\(oneDouble),twoDouble:\(twoDouble)")// oneDouble:20.02,twoDouble:10.01
    这个例子用泛型完美的解决了上述的问题,只需要定义一个泛型函数,只要保证 传入的两个参数是同一个类型,就不用根据传入参数的类型不同而写不同的方法。

    3.类型参数

    在上面的泛型函数例子中,占位符T是类型参数的一个例子。类型参数指定并命名一个占位符类型,并用<>包裹,放在函数名后面。一旦一个参数类型确定,就可以指定参数类型,或者返回值的类型,还可以用作函数体的注释类型。在调用的时候会被实际的类型替代,如传递的是Int,就替换为Int,如果传入的是Double类型就替换为Double等等

    4.命名类型参数

    上面的泛型例子的 T,只是一个描述性的名字,通常用单一的字母来命名,例如:T、U、V等。T代表只是一个占位符,命名规则同驼峰命名法

    5.泛型类型

    除了定义泛型函数,还可以定义泛型类型。如Array,Dictionary的用法
    下面展示一个非泛型版本栈
    struct IntStack {
        var items = [Int]()
        mutating func push(item: Int) {
            items.append(item)
        }
        mutating func pop(item: Int) -> Int {
            return items.removeLast()
        }
    }
    这个是一个泛型版本的栈
    struct Stack<T> {
        var items = [T]()
        mutating func push(item: T) {
            items.append(item)
        }
        mutating func pop(item: T) -> T {
            return items.removeLast()
        }
    }
    首先在函数名后面加<泛型类型名>,<>里面表明类型参数名。然后在函数主体里面完成跟非泛型栈类似的功能。这样这个泛型结构体就不只能压栈Int类型的值,还可以是其它类型
    var stack = Stack<String>() //要在类型名后面加<类型名>
    stack.push("uno")
    stack.push("dos")
    stack.push("tres")
    stack.push("cuatro")
    
    print(stack.pop()) // cuatro

    6.扩展一个泛型类型

    可以扩展一个泛型类型,给这个泛型类型添加属性、方法、下标等。
    extension Stack{
        //给泛型Stack扩展一个计算型属性topItem,返回最上面的item
        var topItem: T? {
            return items.isEmpty ? nil : items[items.count-1]
        }
    }

    7.类型约束

    在上面的SwapTwoVlues 和 Stack中,可以作用任何类型。但是也可以添加一个约束,比如指定一个类型必须采纳某协议或者是指定类等。在Swift中(Bool,Int,Doube,String默认都是哈希的),Dictionary的键就需要必须是可哈希的,方便字典查找是否已包含某个键的值。
    类型约束语法
    可以在类型参数名后面加一个类型或者协议名,通过冒号隔开,多个类型参数之间用逗号隔开
    func somFuntion<C:NSObject, P: NSObjectProtocol>(someClass: C, someProtocol: P){
        //这里用NSObject和NSObjectProtocol做例子
    }

    在定义的这个函数中,有两个类型约束,第一次类型参数C代表是某个类,第二个参数P代表某个协议。

    类型约束实践

    这个非泛型类型的方法用来查找某个字符串是否在字符数组中,存在返回index
    func findStrInArray(_ array: [String], strToFind: String) -> Int?{
        for (index,value) in array.enumerated(){
            if strToFind == value{
                return index
            }
        }
        return nil
    }

    下面这是针对上面非泛型方法泛型版本的方法
    func findIndex<T: Equatable> (_ array: [T], _ valueToFind: T) -> Int? {
        for  (index,value) in array.enumerated(){
            if value == valueToFind { //如果没指定S:Equatable 这句话会编译不通过
                return index
            }
        }
        return nil
    }

    在这个泛型例子中,不是所有的类型都可以 用 == 来比较的,所有必须指定泛型类型参数的约束为 Swift提供的 Equatable 协议,这表示T代表的类型必须是支持 Equatable 协议的。所有的Swift标准类型默认都是支持Equatable协议的.
    let value = findIndex([3.14159, 0.1, 0.25], 9.3)
    // doubleIndex 类型为 Int?,其值为 nil,因为 9.3 不在数组中
    let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
    // stringIndex 类型为 Int?,其值为 2

    8.关联类型

    在定义协议的时候,有时候用一个或者多个关联类型作为定义协议的一部分,关联类型作为协议的一部分,为某个类型提供了一个占位符,其实际类型会在采纳的时候被指定。并用关键字typealias 关键字来指定关联名

    关联类型实践

    下面定义一个协议,协议指定了一个关联类型
    protocol Container{
        associatedtype itemType //声明一个关联类型
        mutating func appended(item: itemType)
        var count: Int{ get }
        subscript(i: Int) -> itemType { get }
    }
    下面是非泛型的版本采纳 Container 协议
    struct intStack: Container {
        // IntStack 的原始实现部分
        var items = [Int]()
        mutating func push(item: Int) {
            items.append(item)
        }
        mutating func pop() -> Int {
            return items.removeLast()
        }
        //这里没设置关联类型的原因是根本不需要设置,因为很确定只返回Int型,当然你设置了也没问题。
        // Container 协议的实现部分
        mutating func appended(item: Int) {
            self.push(item: item)
        }
        var count: Int {
            return items.count
        }
        subscript(i: Int) -> Int {
            return items[i]
        }
    }

    下面是一个泛型版本的
    struct genericStack<T>: Container{
        // genericStack<T> 的原始实现部分
        var items = [T]()
        mutating func push(item: T) {
            items.append(item)
        }
        mutating func pop() -> T {
            return items.removeLast()
        }
        
        //这是设置关联类型具体是什么类型
        typealias itemType = T
        
        // Container 协议的实现部分
        mutating func appended(item: T) {
            self.push(item: item)
        }
        var count: Int {
            return items.count
        }
        subscript(i: Int) -> T {
            return items[i]
        }
    }

    通过扩展一个存在类型来指定关联类型

    通过扩展添加协议的一致性描述了如何利用一个已存在类型符合一个协议,这包括了使用关联协议
    Swift中的Array都满足了Container协议的要求,意味着可以扩展Array采纳Container协议,你可以通过一个空扩展来实现这点.
    extension Array :Container{
        mutating internal func appended(item: Element) {}
    }
    定义这个扩展之后,可以用Array当做Container类型使用。

    9.Where子句

    类型约束能够让我们为泛型类型添加一些约束和条件。为关联类型添加一些约束也是很有必要的。可以在参数列表中使用where子句来为关联类型添加约束。
    下面的例子判断两个采纳Container协议的类型是否所有的元素顺序及值都相等。
    func allItemsMatch<C1: Container,C2: Container>(someContainer: C1,_ anotherContainer: C2) -> Bool where C1.itemType == C2.itemType, C1.itemType: Equatable {
        if someContainer.count != anotherContainer.count {
            return false
        }
        for i in 0...someContainer.count-1{
            if someContainer[i] != anotherContainer[i]{
                return false
            }
        }
        return true
    }
    这个泛型函数在类型参数里面添加了where子句约束,C1,C2都必须是采纳Container协议的类型,并且C1、C2的泛型类型必须相同,而且C1的泛型类型必须是采纳Equatable的。
    var stackOfStrings = genericStack<String>()
    stackOfStrings.appended(item: "uno")
    stackOfStrings.appended(item: "dos")
    stackOfStrings.appended(item: "tres")
    
    var arrayOfStrings = ["uno", "dos", "tres"] //array类型的满足Container类型,参考上面的extension Array
    
    if allItemsMatch(stackOfStrings, arrayOfStrings) {
        print("All items match.")
    } else {
        print("Not all items match.")
    }
    //结果是:All items match.


    展开全文
  • 问题 1:我能否写一个 Swift 函数用于查找在任意数组中存储的任意类型的任何实例对象的位置\索引。 问题 2:我能否写一个 Swift 函数用于确定在任意数组中存储的任意类型的任何实例对象的类型。 我所说的 “任何...
  • OC见过离散型网络框架,项目用...所以就萌发了自已写一个Swift离散型网络框架,然后给组员分享一波Swift和架构思想。 先来看一张前期思维导图 整个项目基于Swift(开始4.2半个月前出了5.0也兼容) Alamofi...
  • 1.3 Swift语言演进 2020-06-15 13:34:27
    1.3 Swift语言演进 小荷才露尖尖角,早有蜻蜓立上头 长风破浪会有时,直挂云帆济沧海 俗话说得好:要想掌握一门学科先关注它的发展史,同样的,要想学好一门语言先看它的进化史。 任何一门卓越的语言,都有其独特...
  • swift中网络请求库的封装(Alamofire+HandyJSON) 我们用swift语言来写iOS的程序,会用Alamofire+HandyJSON来取代AFNetworking+MJExtension,怎么样封装成正确姿势来发起网络请求,我个人封装一个,有待优化的地方,还...
  • 【导语】Swift 自发布以来就备受众多 Apple 开发者关注,但由于 API 尚不稳定,系统没有内置 Framework 导致 App 包增大等问题,使得线上主力使用的公司还很少,不少客户端开发者都还没有机会使用 Swift 进行开发。...
  • Swift学习笔记 (三十) 扩展 2019-08-20 14:01:32
    扩展可以给一个现有的类,结构体,枚举,...(与 Objective-C 分类不同的是,Swift 扩展是没有名字的。) Swift 中的扩展可以: 1.添加计算型实例属性和计算型类属性 2.定义实例方法和类方法 3.提供新的构造...
  • WCDB 作为微信的终端数据库,从 2017.6 开源至今,共迭代了 5 个版本。我们一直关注开发者们的...而这其中,呼声最高的莫过于 对 Swift 的支持。 WCDB ObjC 版本的实现中,由于引入了 C++ 代码,并不能直接 bridge ...
  • IOS数据存储 之WCDB (二)WCDB.swift使用篇 上一篇:IOS数据存储 之WCDB (一)讲解了WCDB的一些特性,重点讲解了对比FMDB的用法,但是这些用法基本都是面向OC语言的。本篇主要讲解Swift语言版本基本使用。 ...
  • 新年新语言,WCDB Swift 2018-01-03 13:09:04
    而这其中,呼声最高的莫过于 对 Swift 的支持。 WCDB ObjC 版本的实现中,由于引入了 C++ 代码,并不能直接 bridge 到 Swift。因此,我们从 9 月份开始就着手使用原生的 Swift,重写 WCDB。并于 10.
  • 欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:sanhuazhang,此文发布在微信终端开发团队的专栏 ...而这其中,呼声最高的莫过于 对 Swift 的支持。 WCDB ObjC 版本的实现中,由于引入了 C++
  • 在2015年的时候苹果刚推出swift1.0不久,当时毕竟是新推出的语言,大家也都很有激情的学习。不过在学完后发现很难在实际项目中使用,再加上当时公司项目都是基于OC来做的开发,就把swift放一边了。  后来也不断...
  • 回顾一下熟悉的OC首先创建一个类实现方法如下:而当我们利用构造函数生成实例时有以下几种方法在OC的例子中,构造器initWithName: age: 内部调用了另一个构造器,避免了代码重复,下面来围观Swift中如何实现。...
  • Swift 是猴还是猿? 2019-08-08 10:29:07
    欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦...Objective-C经过岁月的洗礼其稳定性、性能和开发特性支持度都是比较成熟的,Swift在这些方面是否已经比较完善,开发者是否可以开始着手大面积使用Swift进...
1 2
收藏数 25
精华内容 10