Swift 泛型简单应用

2017-01-13  本文已影响0人  效宇笑语

泛型从字面来理解就是一种泛指的类型,通过在类、方法、接口等指定泛型的类型,可以避免重写,达到重用的目的,而且可以通过泛型限制某些变量的类型,本文通过几个例子来阐述泛型在实际应用开发中的作用,并从以下几个方面介绍:

<h1>(1)泛型定义 </h1>

<h1>(2)泛型方法 </h1>

<h1>(3)泛型接口 </h1>

<h1>(4)泛型类 </h1>

<h2> 一、泛型定义 </h2>

通过尖括号指定泛型类型<T>,其中的T就是将要表示的类型被称为占位符,swift的泛型可以指定任意类型,Int,String等。

<h2> 二、泛型方法 </h2>

下面通过一个程序来介绍泛型方法,该方法用于交换两个相同类型的值。

1.交换两个Int类型的值

 func swapTest(inout a : Int , inout b: Int) {
    let c: Int = a
    a = b
    b = c
}
var a = 10
var b = 20
swapTest(&a, b: &b)

2.交换两个String类型的值

func swapTest(inout a : String , inout b: String) {
    let c: String = a
    a = b
    b = c
}
var a = "Tom"
var b = "Jerry"
swapTest(&a, b: &b)

此时就会发现问题,当每次新增一种类型时,就需要再写一个功能相同的函数,就会出现冗余,为了解决相同功能的函数在不同类型的对象间代码公用,那么我们需要使用泛型函数:

func swapTest<T>(inout a : T , inout b: T) {
    let c: T = a
    a = b
    b = c
}
var a = 10
var b = 20
swapTest(&a, b: &b)
var aString = "Tom"
var bString = "Jerry"
swapTest(&aString , &bString)

通过指定占位符来实现泛型函数,其中的T就为占位符,也就是说,函数在声明的时候并没有制定类型T,该类型需要在调用的时候指定,再看看此时函数的参数,也是通过占位符来限制a、b的类型相同。当调用函数swapTest时,函数会根据传入参数的类型确定T的实际类型。
当然泛型的占位符可以根据需要指定多个,例如:

func tuple<T , V>(a: T , b: V) -> (T , V) {
    let tu: (T , V) = (a , b)
    return tu
}

此方法根据指定两个泛型占位符,为调用处返回一个元胞数组。需要注意的是,此处虽然指定了两个泛型占位符,但是不代表T与V的类型一定不相同,可以进行如下调用tuple(10,20)。

<h2> 三、泛型接口(协议)</h2>

泛型接口与泛型方法和泛型类的定义略有不同,泛型接口在定义的时候并不直接通过尖括号声明,而是在接口内部通过associatedtype 并跟一个泛型占位符指定。如下所示

protocol CallBack {
    associatedtype Element
    var callBack: ((callData: Element!) -> Void)? { set get }
    func load(d: Element!)
}

此时Element就是一个占位符,泛型接口与普通的接口不一样,不可以用作变量的类型,只能用于对泛型进行约束,例如说不可以存在如下代码 var c = CallBack<Person>()。实现了该接口的类在进行load后会调用callBack将数据传回调用出。

<h2> 四、泛型类 </h2>

泛型类的定义如下所示:

class PrjObj: NSObject {    
     override init() {        super.init()    }   
     func test() {            }
}
class Test<T: PrjObj>: NSObject{
    var testObj: [T]!
    init(testObj: [T]) {
        super.init()
        self.testObj = testObj
    }
    func testObjFunc()  {
        for one in self.testObj {
            one.test()
        }
    }
}

通过声明Test类,该类的泛型占位符只接受PrjObj的子类,用于进行项目相关类的测试。只要是PrjObj的子类,就可以加入到数组中,进行测试。

<h2> 泛型的实际应用:</h2>

下面让我来模拟一个实际应用的场景,当网络请求成功后,将数据回调(仅仅是模拟)。
首先需要一个回调接口

protocol CallBack {
    associatedtype Element
    var callBack: ((callData: Element!) -> Void)? { set get }
    func load(d: Element!)
}

就像协议泛型所描述的,该协议的作用是限制实现了协议的类的功能,当位于服务层的网络请求响应成功后,会调用load方法,load方法的作用是调用callBack,将数据回溯至相关页面。

class Implement<T>: NSObject , CallBack {
   typealias Element = T
   var data: T!
   var callBack: ((callData: T!) -> Void)?
   func load(d: T!) {
       self.data = d
       self.callBack?(callData: self.data)
   }
}

Implement类为实现了CallBack接口的泛型类,并实现了load方法,load方法将设置data值,并将调用callBack。

class CarListener: Implement{    
    static let instance: CarListener = CarListener()
}
class PersonListener: Implement{
    static let instance: PersonListener = PersonListener()
}

声明两个Lisener的实现类,用来发送和接受相关类型的回调,PersonListener只负责用于Person类的回调,CarListener只负责Car类的回调

class DispatchReceive {
    var personListener: PersonListener = PersonListener.instance
    var carListener: CarListener = CarListener.instance
    func onMessage(person: Person!) {
    }
    func onMessage(car: Car!) -> Void {
    }
    init() {
        self.personListener.callBack = onMessage 
        self.carListener.callBack = onMessage
    }
}

DispatchReceive定义PersonListener 和 CarListener具体的回调方法,当相关的数据从服务器返回,会调用各自的onMessage方法,传入不同的参数。

class DispatchPost {
    // data from server
    func receivePersonFromServer() {
        PersonListener.instance.load(Person())
    }
    func receiveCarFromServer() {
        CarListener.instance.load(Car())
    }
}

DispatchPost 服务器返回数据,通过调用load方法将消息分发出去。

上一篇下一篇

猜你喜欢

热点阅读