学习目标
由于已经有了Java编程思想,所以着重了解Swift语言特有的特性,与Java不一样的地方。最终目的是可以使用Swift语言开发iOS应用。
学习过程
- [阅读苹果官网Swift文档](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html)
- 使用Xcode动手尝试运行部分代码。
- 文档总结
学习内容
The Basics [Swift概览]
Swfit是类型安全的语言。变量的类型是确定的。不同于PHP,PHP类型是不确定的。
Swift结束不用添加分号;,这点与Java不同。
数据类型。Swift的基础数据类型有表示整型的Int,表示浮点型的Double和Float,表示布尔值的Bool,表示字符串的String。集合类型有标识数组的Array,表示无序集合的Set,表示映射关系的Dictionary。Swfit还提供自己特有的类型:元组.元组没有具体的关键字,表达形式是(value1,valule2...);
-
声明方式。Swift的声明方式只有两种,通过关键字 let和var。这点区别与Java的变量声明。let声明的变量类似于Java通过final声明的变量,不可修改。var声明的变量可以被修改。声明的变量,使用前必须初始化(可选类型除外)。下面是变量max的几种声明方式:
let max = 10; //明确了 max的类型是Int. let max :Int ://同样明确了max的类型是Int.因为这里没有确定初始值,所以使用前必须赋值,否则会报错。 var max = 10//max可以改变成其他值,而let声明的就不可以。
-
在字符串中连接变量值可以通过 (变量名称)方式。例如
let name = "Zhouztashin"; NSLog("my name is \(name)");
Int类型区分。Swift语言,Int类型同样有有符号和无符号的区分和位数的区分。一般,我们使用Int就可以了,当前平台是32位,它就是32(Int32)的。无符号的Int类型U开头,例如UInt32。
Double表示64位的浮点数,Float表示32位的浮点数。
-
类型别名。Swift提供类型别名的机制,提高代码可阅读性。使用关键字 typealias可以为类型指定别名:
typealias AudioSample= UInt16;//为UInt16指定别名。
可选概念。Swfit里面有一个"Optionals"概念。例如某个变量可以有值,也可以没有值。这就是可选的概念。没有值使用nil表示。使用?符号声明的变量就是可选变量,可选变量可以被赋值为nil。非可选变量不能为nil。
-
可选概念使用方式。Swfit提供了一种可选概念的使用方式:
//语法 if let 变量名 = 可选语句{ //如果赋值最终不等于nil 则执行这里的语句 }else{ //赋值等于nil ,则执行这里。 }
//例子 //强制转换 字符串 "not Number"为Int,结果是失败,所以number =nil; if let number = Int("not Number"){ //由于number=nil,所以这里不会被执行 }
Swfit也提供了异常处理机制,类似于Java的异常处理机制。
Basic Operators [Swfit 操作符]
- 各类操作符与Java是一致的。
- 操作符号的左右两边要留出空格,不然会报错。
- nil值操作符。Swfit提供了??操作符。
let valueA = "A"; var valueB: String? var result = valueB ?? valueA; //如果valueB 为nil,那么就将valueA的值给result.
- 范围操作符。Swfit提供范围操作符号"a...b".指定了 从a到b。
for index in 1...5{ //这里循环5次,从1到5。 }
- 半开范围操作符。Swift提供了半开操作符 "a..<b",类似于范围操作符。
for index in 0..<10{ //循环10次,从0到9. }
Strings and Characters [字符和字符串]
- 字符串声明方式。
var emptySting = ""; var anotherEmptyString = String();
- 字符声明方式。
let singleChar : Character;
- 字符串是值类型。不是引用类型。这一点需要与Java区分。
- 字符串拼接。字符串拼接可以通过"+";
- 可以通过 (变量)方法在字符串里面嵌入变量值。例如
let name = "Zhouztashin"; print("My name is \(name)");//会打印出 My name is Zhouztashin。
- Swift提供了判断是否有相同前后缀的功能。例如。
let str1 = "LiXX"; let str2 = "ssLi";
- Swfit提供了Unicode的访问形式。"\u{代号}"
- 常用方法。
var name = "Zhouztashin"; 1、name.isEmpty //空判断 2、for character in name.characters{//遍历打印字符 print(character);//打印单个字符 } 3、name.count;//获取字符串数量 4、name[index];//获取某个下标位置的字符 5、name.insert("My name is",at :0);//在下标0的位置插入字符串。 6、name.remove(at :0);//移除下标为0的字符。 7、name.hasPrefix("Zhou") // 前缀判断,因为有前缀Zhou,所以结果为true; 8、name.hasSuffic("shin")//因为有后缀shin,所以结果为true;
Collection Types [集合]
- 集合数据类型。Swift提供了三种集合的数据类型。Array,Set,Dictionary。其中Array类比于Java的列表和数组,Set类比Java的Set,Dictionary类比Java的Map。
- 集合可变与不可变。不同于Java语言,因为Swift集合类型是值类型,所以,Swfif的集合类型如果被声明为let的话,该集合本身和其包括的数据均不能变动。
- 集合元素访问&赋值方式。Array可以通过数字下标方式访问和赋值,Set则需要通过特定的SetIndex<>下标访问。Dictionary可以通过Key以下标的方式访问相应值。
- 集合通用方法。空判断(isEmpty)和获取数量(count)的方法是通用的。
- Array声明方式:
var someInts :Array<Int>;//声明一个未初始化的Int 列表类型。 var someInts :[Int];//简约声明方式。 var someInts = [Int]();//简约初始化空方式。 var someInts = [];//当someInts已声明了具体类型,那么可以通过[]将该列表置为空 var someInts = [12,23];//简约初始化赋值方式。 var threeDoubles = Array(repeating :0,0,count:3);//特定声明方式,结果会生成 [0,0,0,0,0,0];
- Array常用方法。与第2节字符串操作所用的方法是一样的。
- Array遍历方式:
var someInts = [1,2,3]; 1)、遍历元素 for item in someInts{ print(item);//打印1,2,3 } 2)、遍历下标和元素 for (index, value) in someInts.enumerated(){ print("\(index) AND \(value)"); }
- Set声明方式:
var someInts :Set<Int>;//声明一个未初始化的Int 列表类型。 var someInts :Set = [Int]();//简约初始化空方式。 var someInts = [];//当someInts已声明了具体类型,那么可以通过[]将该列表置为空 var someInts :Set = [12,23];//简约初始化赋值方式。
- Set常用方法。与第2节字符串操作所用的方法是一样的。
- Set遍历方式。与Array类似。
- Dictionary声明方式:
var someDictionary = String : String;//声明一个字符串与字符串的映射字典。
var someDictionary :[String : String];
var someDictionary = ["Zhou":"ZeXuan","Zhong":"Hong"];//以:符号分割键值对。
var simeDictionary = [:];//将该字典变量置为空。 - Dictionary常用方法:
var someDictionary = ["Zhou":"ZeXuan","Zhong":"Hong"]; 1)、更新键值对。[也可以通过下标方式] someDictionary.updateValue("Yong",forKey:"Zhong");//更新键为Zhong的值为 "Yong"; 2)、移除键值对。 someDictionary.removeValue(forKey:"Zhong");//移除键为Zhong的键值对。
- Dictionary 遍历方式:
var someDictionary = ["Zhou":"ZeXuan","Zhong":"Hong"]; //遍历获取键值对 for (key,value) in someDictionary{ print("\(key),\(value)");//打印出 Zhou,ZeXuan。Zhong,Hong。 } //遍历键。 for key in somDictionary.keys{ print(key);//打印键。 } //遍历值 for value in someDictionary.values{ print(value);//打印值 }
- 获取键值对列表。通过 let keys = [String] ta(someDictionary.keys) 获取键列表。值也一样,不过把调用的方法从keys改为values。
Control Flow [控制流程]
Swift提供了的判断流程、循环流程,选择流程。这里仅列出常用的使用方式。
Swift提供了continue,return,break跳出当前控制流程。与Java一致。
-
判断流程。与Java类似,采用if else关键字。不同的是不需要使用()将条件包括起来。
//语法格式 if 条件 { }else{ } //例子 var year = 1; if year == 1 { print("我一岁");//打印此语句. } else{ }
-
选择流程。选择流程也与Java类似,采用switch cas关键字。不同的是Swift的switch不需要break;语句跳出当前匹配代码段。如果需要延续下面匹配值的代码段,则需要使用fallthrough语句,只会延续一个匹配值。
//语法格式。 switch 值 { case 值1: 执行代码段; case 值..: 执行代码段; default: 未匹配到则执行这里。 } //例子: var year =1; switch year{ case 1: print("我1岁"); case 2: print("我两岁"); } //结果是打印 我1岁;
-
循环流程。Swift同样提供了for 跟while 循环语句。while语句与Java一致。这里只说for语句
//语法格式 for 变量 in 范围{ } //其中范围采用了Swfit特有的范围操作符。 //例子 for index in 1...10{ print(index);//打印1到10.如果需要只打印1到9,那么应该使用 1...<10。 }
-
Swfit提供了简约的变量赋值语句。使用了关键字guard。
//例子 guard let name = Int("Zhou") else{ //赋值不成功则执行这里。 }
Functions [方法]
- Swift方法声明与调用方式。Swift的调用方式与Java有一些区别,Swfit调用方法需要指定相应的参数名称。
//声明格式。 func 方法名 (参数名:参数类型,...) ->返回值类型{ return; } //例子。 func isNumber2(number : Int) ->Bool{ if number ==2 { return true; }else{ return false; } } //调用 let is2 = isNumber2(number: 2);//调用的时候需要指定参数名称。 print(is2);//输出true;
- 调用方法不需要输入参数名称的方式。通过在参数名称前面添加 "_"符号就可以在调用的时候不指定参数名称。例如
//调用时:isNumber2(2);//由于声明的时候参数添加了 "_",所以不需要参数名称。 func isNumber2(_ number :Int) ->Bool{ ...}
- 默认参数值。可以为参数指定默认值。通过在声明的时候赋值,就可以为参数添加默认值。
//为参数number添加了默认值 3,调用的时候可以不用传入该参数值。 func isNumber2 (number :Int = 3) ->Bool{...}
- 可变的参数值。可以为不指定参数的数量。声明的时候添加"...".例如:
//可变的参数声明。调用的时候可以传入不等长度的参数。例如 isNumber2(12.3,34.4); isNumber2(12.4); func isNumber2(number : Double ...)->Bool{};
- in-out 参数方式。类似于C语言中的引用传递。由于Swift Int等基本类型是值类型,所以在方法中改变该值只在该方法范围内有效。而通过指定参数为inout类型,那么就会影响到方法外该变量的值。
- 方法也可以是一个变量参数。Swift提供了一个特性,方法也可以是一个变量或者参数。
Closures [闭包]
- 闭包的应用之一,参数为方法的时候的简约调用方式。
//语法 { (参数) -> 返回值 in 代码段 } //例子 let array = ["Str1","Str2"]; array.sorted(by: {(s1:String,s2:String)->Bool in return s1>s2}); //更简约的方式 array.sorted(by :{ s1,s2 in return s1 >s2});//因为参数和返回值是确定的所以不用再描述。
Enumerations [枚举]
- Swift提供的枚举类型跟Java类似。但是比Java要更加好用些,例如Swfit可以给枚举项直接添加对应值。
//语法。 enum 枚举名称{ case 枚举项 case 枚举项2 } 或者 enum 枚举名称{ case 枚举项1,枚举项2,枚举项3.. } //例子 enum CompassPoint{ case north case south case east case west } //引用方式 var directionTohead = CompassPoint.north; directionTohead = .east;//因为变量指定了CompassPoint类型,所以可以用这种简约的赋值方式。
- Swfit提供给枚举类型添加相应的值。
//语法 enum 枚举名称 : 值类型{ case 枚举项 = 值; case .. } //例子 enum Planet : Int{ case mercury = 1, venus;//mercury 对应的值为 1; } //引用方式 let mercuryValue = Planet.mercury.rawValue;//通过关键字rawValue获取值。
- 可以通过枚举类的值获取对应的枚举项。
let somePlanet = Planet (rawValue : 1);//这里查找值为1的枚举项,结果为mercury。
Classes and Structures [类和结构体]
- Swift提供了两种块结构。类和结构体。类与结构体的结构和作用是类似的,只不过在不同的应用场景下需要选择相应的结构。这两者跟Java的类是类似的,都由成员变量,成员方法构成。但是区别于Java的是类的文件名称跟里面实际声明的类的名称并不需要一致。
- 声明方式和实例化方式
//声明方式 1) struct 结构体名称{ //结构体声明方式 //变量 //方法 } 2) class 类名称{ //类声明方式 //变量 //方法 } //实例化 struct Circle { var width :Int; var height :Int; } let circle = Circle();//实例化类或者结构体
- 类和结构体的区别。
1)、类是引用类型。而结构体和枚举类是值类型。
2)、结构体倾向用于封装一些简单的数据。
3)、类可以继承,而结构体无法被继承。
4)、类和结构体的存储成员变量(区别与计算变量)需要在声明或者在构造函数中被初始化,否则会报错。如果有一个存储成员变量没有初始,那么在实例化的时候需要通过这个全量结构函数传入所有值,否则会报错。类和结构体默认添加了一个全量的初始化方法。 - 判断类指向同一个实例。通过“===”和“!==”判断两个变量是否引向同一个实例。
- Swift的String、Array、Dictionary、Set都是结构体,所以他们都是值类型。
Properties [属性/成员变量]
- Swfit将属性按照作用分为两类,一类是存储变量,一类是计算变量,这与Java的成员变量区别很大的一点。另外跟Java一样,Swift也有成员变量和类变量的区分,一样使用static 修饰词。
- 存储变量与Java的成员变量是一致的。计算变量的声明方式
struct Point{ var x = 0,0,y = 0.0; } struct Rect{ var origin = Point(); var center :Point{ //center则是Swift语法中的计算变量。重新定义了获取和赋值的操作。 get{ return Point(x :2.2,y:23.3); } //如果没有写newCenter,那么默认设置的变量名是newValue,如果没有写set方法,就说明该计算变量只可读。 set(newCenter){ origin.x = 2; origin.y = 3; } } }
- Swift成员变量调用方式。
struct Point{ var x = 0.0,y = 0.0; } var point = Point(); let x = point.x;//获取成员变量x的值。 point.x = 1.3;//更改成员变量x的值。
- 成员变量观察者。成员变量支持赋值改变前后的观察通知。通过willSet 和 didSet方法可以得知成员变量被改变的前后。
//语法 class 名称{ var 变量 :类型{ willSet(新的变量值名称){ //改变值前的回调 // } didSet{//改变值后的回调 } } }
Methods [方法]
- 方法类型。Swift中的方法跟Java一样也分为实例方法和类方法。跟Java一样,类方法也是通过添加static修饰词。
- 关键字 self.self代表结构体、类本身。与Java的this关键字相似。
- 方法内改变成员变量值。在结构体或者枚举类里面不可以直接改变成员变量值,需要使用关键字 mutating修饰方法才可以修改成员变量。
Inheritance [继承]
- Swift中的类可以被继承。跟Java一样,也支持多态。
//语法 class 名称 : 父类名称{ // } //例子 class Father { } class Son : Father{ }
- 重写方法。Swift一样可以重写父类的方法。通过关键字override。
- 调用父类的方法和成员变量。通过关键字super可以调用父类的方法和成员变量。
- 重写成员变量。不但可以重写方法,Swift也可以重写成员变量的方法和观察者。
//例子 class 类名称{ override var current :Double{ //重写的时候需要重新声明变量。 didSet{ // } } }
- 同样,通过final 声明可以防止重写。
Initalizers [初始化]
- 初始化类似于Java的构造函数。与Java用类名表示构造函数不同的是,Swift通过 init表示构造函数。
- Swift将构造函数分为了两类,一类是Designated 初始化方法 和Convenience初始化方法。其中Designated就是Java中的构造函数,Convenience就是Swift对外调用提供的简约式声明方式,convenidence修饰的构造方法必须调用Designated 方法。这样重载简约的构造方法的逻辑会清晰很多,因为一定会调用普通的构造方法。
- Swift还提供可选式样的构造函数,类似于Option值。
Deinitialization [析构函数]
- 类似与Java类中的finalize函数。当该类实例被回收的时候就会调用该方法。方法的声明方式:
deinit{ //处理代码 }
Automatic Reference Counting [自动引用计数器]
- Swift也跟Java一样也有对引用的自动回收机制。
- Swift引用计数原理。Swift的引用计数系统会跟踪属性、常量、变量对类实例的引用,如果有存在一个引用以上,则不销毁该实例。
- 强引用循环问题。Swfit会出现强引用循环的问题,就是类实例A引用了类实例B,两者相互引用。Swift提供的解决方案是使用weak修饰符让变量成为弱引用。与Java的弱引用同出一辙。
Error Handing [异常处理]
- Swift同样提供了异常处理的机制。跟Java的异常机制类似。
1)、抛出异常. func throwsException () throws { throw 异常信息 } 2)、不处理异常,继续抛出异常 func throwsExceptionGoOn ()throws{ try throwsException(); } 3)、处理异常。 func handleException(){ do { try throwsException();//这里可能抛出异常 }catch(){//匹配异常 //处理异常。 }catch(){ //处理异常2 } }
- Java有finally{}模块可以确保一些结束操作可以被执行,而Swift也提供了类似的机制,通过defer关键字可以确保里面的代码段在最后被执行。需要注意的是defer句子应该在异常代码之前被声明。并且会先于catch模块前执行。
func processFile(filename : String) trhows{ let file open(filename); defer{ //这里的代码段会在该范围内所有代码都执行完毕才执行。 close(filename);//执行关闭操作。 } }
Type Casting [类型转换]
-
Swift提供了两种类型转换相关的语法。一种是判断,一种是转换。通过 is 关键字可以判断某个变量是否是某种类型,通过 as? 和 as!转换类型。is类似与Java InstanceOf的关键字,as类似与Java中的强制转换()。
1) 、is。判断某个变量是否是某种类型或者某种类型的子类。 class Animal{ } let animal = Animal(): if(animal is Animal){ //这里会执行。 } 2)、as? 和as! 可以将类型转换为某种类型。 class Animal { } class People : Animal{ } let people = People(); let asAnimal = people as? Animal;//现在asAnimal 是 Animal类型了
Swift提供了两种任意类型。Any 和AnyObject。其中可以将任何类型的变量转为Any,包括方法。而AnyObject可以代表任意一个类实例。其中AnyObject类似与Java的基类Object.
Extensions[扩展]
- 扩展是Swift提供的新特性。可以为类、结构体、枚举类、协议扩展新的功能,不同于继承,扩展没有继承层级上的关系。可以当作是附加衍生。
- 可扩展的内容:
1)、计算性成员变量。
2)、实例方法与类型方法
3)、新构造方法
4)、下标
5)、实现协议 - 扩展语法。
1)、extension SomeType : Protocol1,Protocol2{ //添加扩展内容 } 2)、实例。为Double添加类型扩展。 extension Double{ var km:Double{return self* 1000_0.0}// } let onInch = 25.6.km;//km是新扩展的计算成员变量。
Protocols[协议]
- 协议与Java中接口的概念是一致的。Swift协议中定义了包括方法、成员变量、类型变量的蓝图。与Java接口不同的是,协议不但可以定义方法,还可以定义成员变量。
- 协议声明与实现:
//协议语法 protocol Nametocol : class{.//如果添加了 class关键字,说明该协议只可以被类实现。 var fullName :String {get } statc func someType();//类型变量,也就是Java的静态变量 func someMethod(); mutating func toggle();//可更改内部变量值的方法 init()//初始化方法 //可选实现。通过添加@objct optional 关键字修饰, 该方法可以不实现。 @objc optional func optionalMethod(); } ` //协议实现 class MyName :NameProtocol{ //这里需要实现协议包含的所有内容,区分与Java这里的方法实现不需要添加override关键字 }
Generics [泛型]
- Swift也提供了泛型,与Java泛型相似。
Access Control [访问控制]
- Swift也提供了访问控制功能。有模块和文件两类访问控制。
- 导入模块。通过import 关键字可以导入并使用该模块功能。与Java类似。
- Swift提供了四种等级的访问控制。分别是public ,internal,fileprivate,private。
- public.public定义的实体可以在自己的模块内被访问,另外其他模块如果导入了该模块,那么其他模块也可以访问该实体。
- internal.internal定义的实体可以在自己的模块内被访问。
- fileprivate。fileprivate定义的实体只能在该文件内被访问。
- private.private定义的实体只能在该实体里面被访问。
- Swift访问控制规则:一个被定义为低访问控制的实体,不能声明为高访问控制等级的任何实例。实体包括变量方法等。。
- 例如定义了一个internal等级的ClassA,不能被声明为 public let classA :ClassA.
- 一个方法的参数和返回值类型定义的访问权限,一定要大于或者等于该方法被声明时候的权限控制等级。
- 跟Java一样,继承后重写的方法不能比父类的方法控制权限大。
- Swift默认为每个实体添加了访问控制:internal.