/** * Protocol(协议)用于统一方法和属性的名称,而不实现任何功能。协议能够被类,枚举,结构体实现,满足协议要求的类,枚举,结构体被称为协议的遵循者。 遵循者需要提供协议指定的成员,如属性,方法,操作符,下标等。 */
//使用protocol来声明一个协议。
/** * 协议的语法 协议的定义与类,结构体,枚举的定义非常相似,如下所示: protocol SomeProtocol { // 协议内容 } 在类,结构体,枚举的名称后加上协议名称,中间以冒号:分隔即可实现协议;实现多个协议时,各协议之间用逗号,分隔,如下所示: struct SomeStructure: FirstProtocol,AnotherProtocol { // 结构体内容 } 当某个类含有父类的同时并实现了协议,应当把父类放在所有的协议之前,如下所示: class SomeClass: SomeSuperClass,FirstProtocol,AnotherProtocol { // 类的内容 } */
protocol ExampleProtocol {
var simpleDescription: String {
get
}
mutating func adjust()
}
//类,枚举和结构体都可以使用协议。
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
//注意在simpleStructure的声明中关键字mutating的使用,它用来标记这个方法修改了这个结构体。而在simpleClass的声明中则不需要使用mutating,因为类中的方法总是可以被修改的。
//二、协议(protocol)
//可定义方法与属性,由具体的类去实现. 越来越像Java
//Swift中的协议能被类,枚举,结构体实现.
protocol SomeProtocol{
//协议内容
}
class SomeClass : SomeProtocol{ //实现协议,可实现多个协议
}
//2.1 协议中属性/方法/突变方法的要求
//2.1.1 属性的要求
protocol AnotherProtocol1{
//class表示类成员(结构体/枚举中用static)
static var property : Int { get set} //get,set 表示可读可写
}
class AnotherClass1 : AnotherProtocol1{
class var property : Int { //实现协议中的属性
get{
return 10
}
set{
}
}
}
//2.1.2 方法要求
//不支持默认参数. 写法上只是没有方法的实现.
protocol AnotherProtocol2{
func myFunc() -> Int //只声明不实现
}
class AnotherClass2 : AnotherProtocol2{
func myFunc() -> Int { //实现方法
return 10
}
}
//2.1.3 突变方法要求
//能在方法或函数内部改变实例类型的方法称为突变方法. (mutating关键字)
//在类中,可以不写mutating,但在结构体与枚举中国必须写
protocol Togg{
mutating func togg()
}
enum OnOffSwitch : Togg{
case Off,On
mutating func togg() { //改变实例的值
switch self{
case .Off:
self = On
case .On:
self = Off
}
}
}
var lightSwitch = OnOffSwitch.Off
lightSwitch.togg() //值变为On
//2.2 协议类型.
// 协议也可以当做类型来使用. 这点和函数一样.
// 1.可作为参数/返回值类型
//2.可作为常量/变量/属性的类型
//3.可作为数组/字典和其他元素类型
protocol MyRect{
func myLuckNumber() -> Int
}
class MyRectImp : MyRect{
func myLuckNumber() -> Int {
return 10
}
}
class Dice {
let sides :Int
var gener : MyRect //作为类型
init(sides:Int,gener:MyRect){ //作为参数
self.sides = sides
self.gener = gener
}
}
var dice = Dice(sides: 6,gener: MyRectImp())
dice.gener.myLuckNumber()
//------------------------extention--------------
//使用extension来为已经存在的类型添加功能,就像新的方法和计算属性一样。你可以用extension为已经声明的类型添加协议,甚至是类库中自带的类型。
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
//使用协议名就像使用其他类型名一样——例如,创建一个不同类型对象的集合,但是这些对象都遵循一个单一的协议。当值的类型是协议类型时,在协议定义以外的方法是不可用的。
//[plain] view plaincopy在CODE上查看代码片派生到我的代码片
let protocolValue: ExampleProtocol = a
protocolValue.simpleDescription
//即使protocolValue有一个运行时类型(simpleClass),编译器同样会把它看作是ExampleProtocol类型。也就是说,你不能访问除了遵循协议以外的类的方法和属性。
//一、扩展(extension)
//扩展 extension (类似OC中的分类,但Swift中没有名字),即在没有权限获取到原始代码的情况下,为类增加新功能.
//注意: 只要定义了扩展,那么该扩展对该类的实例都是可用的.
//extension SomeType{
// //添加到SomeType的新功能写在这里
//}
//1.1扩展属性(只能是计算属性)
//扩展可以添加新计算属性,但是不能添加存储属性(也不可以添加属性观察).
extension Double{ //为API中的已有类型添加实例属性
var km : Double { return self * 1_000.0 }
var m : Double { return self }
var cm : Double { return self / 100.0 }
}
let jjLength = 1.m // 1与m进行点运算,表示1的Double值
let jjLength_km = 1.km
print(10.km + 1.m)
//1.2扩展构造器
//可以定制自己的构造器
class MyClass{
var a : Int
init(){
a = 10
}
}
extension MyClass{
convenience init( parm:Int){ //扩展构造器
self.init()
print("扩展构造器--->便利构造器,\(parm)")
}
}
var myClass = MyClass(parm: 9)
//1.3扩展方法
//下面是像Int中扩展myIntFunc方法
extension Int{
func myIntFunc(){
print("值为\(self),哈哈哈哈!")
}
}
1.myIntFunc()
//1.3.1 修改实例方法
//通过扩展方法,可以修改该实例self本身.但是方法前要加 mutating
extension Double{
mutating func myMoidfySelfValue() {
self = self * self //修改self实例的值
}
}
var d = 2.0
d.myMoidfySelfValue()
//1.4 扩展嵌套类型
//即向已有的嵌套类型中添加新的嵌套类型. 还可以扩展下标(附属脚本)等.
extension Character {
enum Kind{ //嵌套了一个枚举类型
case Big
case Small
}
var k : Kind{
if(String(self).lowercaseString == "a"){
return Kind.Big
}else{
return Kind.Small
}
}
}
var ch : Character = "a"
ch.k //返回一个枚举值Kind.Big
//1.5下标(Subscripts)
//扩展可以向一个已有类型添加新下标。这个例子向Swift内建类型Int添加了一个整型下标。该下标[n]返回十进制数字从右向左数的第n个数字
//123456789[0]返回9
//123456789[1]返回8
//...等等
extension Int {
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 1...digitIndex {
decimalBase *= 10
}
return (self / decimalBase) % 10
}
}
746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7
//如果该Int值没有足够的位数,即下标越界,那么上述实现的下标会返回0,因为它会在数字左边自动补0:
746381295[9]
//returns 0,
//即等同于:
0746381295[9]
//1.6嵌套类型(Nested Types)
//扩展可以向已有的类、结构体和枚举添加新的嵌套类型:
extension Character {
enum Kind1 {
case Vowel,Consonant,Other
}
var kind: Kind1 {
switch String(self).lowercaseString {
case "a","e","i","o","u":
return .Vowel
case "b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z":
return .Consonant
default:
return .Other
}
}
}
//该例子向Character添加了新的嵌套枚举。这个名为Kind的枚举表示特定字符的类型。具体来说,就是表示一个标准的拉丁脚本中的字符是元音还是辅音(不考虑口语和地方变种),或者是其它类型。
//
//这个类子还向Character添加了一个新的计算实例属性,即kind,用来返回合适的Kind枚举成员。
//
//现在,这个嵌套枚举可以和一个Character值联合使用了:
func printLetterKinds(word: String) {
print("'\\(word)' is made up of the following kinds of letters:")
for character in word.characters {
switch character.kind {
case .Vowel:
print("vowel ")
case .Consonant:
print("consonant ")
case .Other:
print("other ")
}
}
print("\n")
}
printLetterKinds("Hello")
// 'Hello' is made up of the following kinds of letters:
// consonant vowel consonant consonant vowel
//函数printLetterKinds的输入是一个String值并对其字符进行迭代。在每次迭代过程中,考虑当前字符的kind计算属性,并打印出合适的类别描述。所以printLetterKinds就可以用来打印一个完整单词中所有字母的类型,正如上述单词"hello"所展示的。
//
//注意:由于已知character.kind是Character.Kind型,所以Character.Kind中的所有成员值都可以使用switch语句里的形式简写,比如使用 .Vowel代替Character.Kind.Vowel@H_827_502@