iOS开发--Swift语言3

协议

协议是对实例行为的一种约束,和ObjC类似,在Swift中可以定义属性和方法(ObjC中之所以能定义属性是因为@property的本质就是setter、getter方法)。和其他语言不同的是Swift中的协议不仅限于类的实现,它同样可以应用于枚举、结构体(如果只想将一个协议应用于类,可以在定义协议时在后面添加class关键字来限制其应用范围)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
protocol  Named {
     //定义一个实例属性
     var  name : String  get  set  }
 
     //定义一个类型属性
     static  var  className : String  get  }
     
     //定义构造方法
     init ( name : String )
     
     //定义一个实例方法
     func  showName ()
     
     //定义一个类型方法
     static  func  showClassName ()
}
 
protocol  Scored {
     var  score : Double  get  set  }
}
 
//Person遵循了Named协议
class  Person : Named  {
     //注意从Named协议中并不知道name是存储属性还是计算属性,这里将其作为存储属性实现
     var  name : String
     
     var  age : Int  0
     
     static  var  className : String {
         return  "Person"
     }
     
     //协议中规定的构造方法,必须使用required关键字声明,除非类使用final修饰
     required  init ( name : String ){
         self . name = name
     }
     
     //遵循showName方法
     func  showName () {
         println ( "name=\( name )" )
     }
     
     //遵循showClassName方法
     static  func  showClassName () {
         println ( "Class name is \"Person\"" )
     }
}
 
//Student继承于Person并且实现了Scored协议
class  Student Person , Scored  {
     var  score : Double = 0.0
     
     init ( name : String score : Double ){
         self . score  score
         super . init ( name name )
     }
 
     //由于上面自定义了构造方法则必须实现协议中规定的构造方法
     required  init ( name String ) {
         super . init ( name name )
     }
     
     func  test (){
         println ( "\( self . name ) is testing." )
     }
}
 
var  p = Person ( name "Kenshin Cui" )
p . showName ()  //结果:name=Kenshin Cui
println ( "className=\( Person . className )" //结果:className=Person
Person . showClassName ()  //结果:Class name is "Person"
p . age = 28
 
var  s : Named = Student ( name "Kaoru" , score : 100.0 //尽管这里将s声明为Named类型,但是运行时仍然可以正确的解析(多态),但是注意此时编译器并不知道s有test方法,所以此时调用test()会报错
s . showName ()
 
//在下面的函数中要求参数stu必须实现两个协议
func  showMessage ( stu : protocol < Named , Scored > ){
     println ( "name=\( stu . name ),score=\( stu . score )" )
}
var  s2 = Student ( name "Tom" , score : 99.0 )
showMessage ( s2 //结果:name=Tom,age=99.0
 
 
//检测协议
let  b1  s  is  Scored  //判断p是否遵循了Scored协议
if  b1  {
     println ( "s has score property." )
}
//类型转化
if  let  s3  s  as Scored  //如果s转化成了Scored类型则返回实例,否则为nil
     println ( "s3' score is \( s3 . score )" //结果:s3' score is 100.0
}
let  s4  =   s  as Scored  //强制转换,如果转化失败则报错
println ( "s4' score is \( s4 . score )" //结果:s4' score is 100.0
  1. 协议中虽然可以指定属性的读写,但即使协议中规定属性是只读的但在使用时也可以将其实现成可读写的;
  2. Swift的协议中可以约定属性是实例属性还是类型属性、是读写属性还是只读属性,但是不能约束其是存储属性还是计算属性;
  3. 协议中的类型属性和类型方法使用static修饰而不是class(尽管对于类的实现中类型属性、类型方法使用class修饰);
  4. 协议中约定的方法支持可变参数,但是不支持默认参数;
  5. 协议中约定的构造方法,在实现时如果不是final类则必须使用require修饰(以保证子类如果需要自定义构造方法则必须覆盖父类实现的协议构造方法,如果子类不需要自定义构造方法则不必);
  6. 一个协议可以继承于另外一个或多个协议,一个类只能继承于一个类但可以实现多个协议;
  7. 协议本身就是一种类型,这也体现除了面向对象的多态特征,可以使用多个协议的合成来约束一个实例参数必须实现某几个协议;

扩展

Swift中的扩展就类似于ObjC中的分类(事实上在其他高级语言中更多的称之为扩展而非分类),但是它要比分类强大的多,它不仅可以扩展类还可以扩展协议、枚举、结构体,另外扩展也不局限于扩展方法(实例方法或者类型方法),还可以扩展便利构造方法、计算属性、下标脚本、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class  Person  {
     var  firstName : String , lastName : String
     var  age : Int = 0
     var  fullName : String {
         get {
             return  firstName + " " + lastName
         }
     }
     
     init ( firstName : String , lastName : String ){
         self . firstName = firstName
         self . lastName = lastName
     }
     
     func  showMessage (){
         println ( "name=\( fullName ),age=\( age )" )
     }
}
 
extension  Person {
     
     //只能扩展便利构造方法,不能扩展指定构造方法
     convenience  init (){
         self . init ( firstName : "" , lastName : "" )
     }
     
     //只能扩展计算属性,无法扩展存储属性
     var  personInfo : String {
         return  "firstName=\( firstName ),lastName=\( lastName ),age=\( age )" ;
     }
 
     //扩展实例方法
     func  sayHello (){
         println ( "hello world." )
     }
     
     //嵌套类型
     enum  SkinColor {
         case  Yellow , White , Black
     }
     
     //扩展类型方法
     static  func  skin ()- > [ SkinColor ]{
         return  [. Yellow ,. White ,. Black ]
     }
}
 
var  p = Person ()
p . firstName = "Kenshin"
p . lastName = "Cui"
p . age = 28
println ( p . personInfo //结果:firstName=Kenshin,lastName=Cui,age=28
p . sayHello ()  //结果:hello world.
Person . skin ()
枚举和结构体

结构体

结构体和类是构造复杂数据类型时常用的构造体,在其他高级语言中结构体相比于类要简单的多(在结构体内部仅仅能定义一些简单成员),但是在Swift中结构体和类的关系要紧密的多,这也是为什么将结构体放到后面来说的原因。Swift中的结构体可以定义属性、方法、下标脚本、构造方法,支持扩展,可以实现协议等等,很多类可以实现的功能结构体都能实现,但是结构体和类有着本质区别:类是引用类型,结构体是值类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
struct  Person  {
     var  firstName : String
     var  lastName : String
     
     var  fullName : String {
         return  firstName  " "  lastName
     }
     
     var  age : Int = 0
     
     //构造函数,如果定义了构造方法则不会再自动生成默认构造函数
//    init(firstName:String,lastName:String){
//        self.firstName=firstName
//        self.lastName=lastName
//    }
     
     func  showMessage (){
         println ( "firstName=\( firstName ),lastName=\( lastName ),age=\( age )" )
     }
     
     //注意对于类中声明类型方法使用关键字class修饰,但结构体里使用static修饰
     static  func  showStructName (){
         println ( "Struct name is \"Person\"" )
     }
}
 
//注意所有结构体默认生成一个全员逐一构造函数,一旦自定义构造方法,这个默认构造方法将不会自动生成
var  p = Person ( firstName "Kenshin" lastName "Cui" age 28 )
println ( p . fullName //结果:Kenshin Cui
p . showMessage ()  //结果:firstName "Kenshin", lastName "Cui", age 28
Person . showStructName ()  //结果:Struct name is "Person"
 
//由于结构体(包括枚举)是值类型所以赋值、参数传递时值会被拷贝(所以下面的实例中p2修改后p并未修改,但是如果是类则情况不同)
var  p2  p
p2 . firstName  "Tom"
println ( p2 . fullName //结果:Tom Cui
println ( p . fullName //结果:Kenshin Cui
  1. 默认情况下如果不自定义构造函数那么将自动生成一个无参构造函数和一个全员的逐一构造函数;
  2. 由于结构体是值类型,所以它虽然有构造函数但是没有析构函数,内存释放系统自动管理不需要开发人员过多关注;
  3. 类的类型方法使用class修饰(以便子类可以重写),而结构体、枚举的类型方法使用static修饰(补充:类方法也可以使用static修饰,但是不是类型方法而是静态方法;另外类的存储属性如果是类型属性使用static修饰,而类中的计算属性如果是类型属性使用class修饰以便可以被子类重写;换句话说class作为“类型范围作用域”来理解时只有在类中定义类型方法或者类型计算属性时使用,其他情况使用static修饰[包括结构体、枚举、协议和类型存储属性]);

类的实例通常称之为“对象”,而在Swift中结构体也可以有实例,因此对于很多二者都可以实现的功能,在文中称之为实例而没有使用对象的概念。

枚举

在其他语言中枚举本质就是一个整形,只是将这组相关的值组织起来并指定一个有意义的名称。但是在Swift中枚举不强调一个枚举成员必须对应一个整形值(当然如果有必要仍然可以指定),并且枚举类型的可以是整形、浮点型、字符、字符串。首先看一下枚举的基本使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//注意Swift中的枚举默认并没有对应的整形值,case用来定义一行新的成员,也可以将多个值定义到同一行使用逗号分隔,例如:case Spring,Summer,Autumn,Winter
enum  Season {
     case  Spring
     case  Summer
     case  Autumn
     case  Winter
}
 
var  s = Season . Spring
 
//一旦确定了枚举类型,赋值时可以去掉类型实现简写
s  = . Summer
 
switch  s  {
case  . Spring //由于Swift的自动推断,这里仍然可以不指明类型
     println ( "spring" )
case  . Summer :
     println ( "summer" )
case  . Autumn :
     println ( "autumn" )
default :
     println ( "winter" )
}

事实上Swift中也可以指定一个值和枚举成员对应,就像其他语言一样(通常其他语言的枚举默认就是整形),但是Swift又不局限于整形,它可以是整形、浮点型、字符串、字符,但是原始值必须是一种固定类型而不能存储多个不同的类型,同时如果原始值为整形则会像其他语言一样默认会自动递增。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//指定原始值(这里定义成了整形)
enum  Season : Int {
     case  Spring = 10  //其他值会默认递增,例如Summer默认为11,如果此处也不指定值会从0开始依次递增
     case  Summer
     case  Autumn
     case  Winter
}
 
var  summer = Season . Summer
 
//使用rawValue访问原始值
println ( "summer=\( summer ),rawValue=\( summer . rawValue )" )
 
//通过原始值创建枚举类型,但是注意它是一个可选类型
var  autumn = Season ( rawValue 12 )
 
//可选类型绑定
if  let  newAutumn = autumn {
     println ( "summer=\( newAutumn ),rawValue=\( newAutumn . rawValue )" )
}

如果一个枚举类型能够和一些其他类型的数据一起存储起来往往会很有用,因为这可以让你存储枚举类型之外的信息(类似于其他语言中对象的tag属性,但是又多了灵活性),这在其他语言几乎是不可能实现的,但是在Swift中却可以做到,这在Swift中称为枚举类型相关值。要注意的是相关值并不是原始值,原始值需要事先存储并且只能是同一种类型,但是相关值只有创建一个基于枚举的变量或者常量时才会指定,并且类型可以不同(原始值更像其他语言的枚举类型)。 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//相关值
enum  Color {
     case  RGB ( String //注意为了方便演示这里没有定义成三个Int类型(例如: RGB(Int,Int,Int))而使用16进制字符串形式
     case  CMYK ( Float , Float , Float , Float )
     case  HSB ( Int , Int , Int )
}
 
var  red = Color . RGB ( "#FF0000" )
 
var  green = Color . CMYK ( 0.61 0.0 1.0 0.0 )
 
var  blue = Color . HSB ( 240 100 100 )
 
switch  red  {
case  . RGB ( let  colorStr ):
     println ( "colorStr=\( colorStr )" )
case  let  . CMYK ( c , m , y , k ):
     println ( "c=\( c ),m=\( m ),y=\( y ),k=\( k )" )
case  let  . HSB ( h , s , b ):
     println ( "h=\( h ),s=\( s ),b=\( b )" )
}

上面提到其实枚举也有一些类型和结构体的特性,例如计算属性(包括类型属性,枚举只能定义计算属性不能定义存储属性,存储属性只能应用于类和结构体)、构造方法(其实上面使用原始值创建枚举的例子就是一个构造方法)、方法(实例方法、类型方法)、下标脚本 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
enum  Season : Int {
     case  Spring = 0  , Summer , Autumn , Winter
     
     //定义计算属性
     var  tag : Int {
         return  self . rawValue
     }
     //类型属性
     static  var  enumName : String {
         return  "Season"
     }
     
//    //定义构造方法,注意在枚举的构造函数中则必须保证self有值(正如类的构造方法必须保证其存储属性有值一样)
//    init(prefix:String){
//        switch prefix.lowercaseString {
//            case "sp":
//                self = .Spring
//            case "su":
//                self = .Summer
//            case "au":
//                self = .Autumn
//            default:
//                self = .Winter
//        }
//    }
     //其实上面的构造器有些不合理,那就是default就是Winter,事实上这类构造器可能传任何参数,此时可以使用可失败构造函数来解决
     //可失败构造函数返回nil(尽管Swift中构造函数是不返回值的,但是此时约定返回nil代表构造失败)
     init ?( prefix : String ){
         switch  prefix . lowercaseString  {
         case  "sp" :
             self  = . Spring
         case  "su" :
             self  = . Summer
         case  "au" :
             self  = . Autumn
         case  "wi" :
             self  = . Winter
         default :
             return  nil
         }
     }
 
     //定义实例方法
     func  showMessage (){
         println ( "rowValue=\( self . rawValue )" )
     }
     //定义类型方法
     static  func  showEnumName (){
         println ( "Enum name is \"Season\"" )
     }
}
 
var  summer = Season . Summer
println ( summer . tag //结果:1
println ( Season . enumName //结果:Season
Season . showEnumName ()  //结果:Enum name is "Season"
summer . showMessage ()  //结果:rowValue=1
 
if  let  spring  Season ( prefix "au" ) {  //可选绑定,构造函数返回值可能为nil
     println ( spring . tag //结果:2
}
原文地址:http://www.cnblogs.com/kenshincui/p/4717450.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值