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