Swift语言
速成文档。本文略去了大部分c语言类似部分,部分java类似部分,小部分python类似部分
写在一个文档里,便于使用Ctrl+F直接查找关键字就可使用
import
如果创建的是 OS X playground 需要引入 Cocoa
如果我们想创建 iOS playground 则需要引入 UIKit
标识符
如果一定要使用关键字作为标识符,可以在关键字前后添加重音符号(`),例如:
let `class` = "biu"
let 用于定义常量,定义完后不能修改。 var 用于定义变量,可以修改。
空格
编码规范要求
let a = b + c
很容易报错,类似
error: prefix/postfix '=' is reserved error: consecutive statements on a line must be separated by ';'
print
public func print(items: Any..., separator: String = default, terminator: String = default)
如果我们想让其不换行输出,只需要将最后一个参数赋值为空字符串即可。
for x in 0...10{ print("\(x) ", terminator: "") } print()
输出结果为:0 1 2 3 4 5 6 7 8 9 10
接收用户的输入可以使用 readLine()
在字符串中可以使用括号与反斜线来插入变量:
import Cocoa var name = "菜鸟教程" var site = "http://www.runoob.com" print("\(name)的官网地址为:\(site)")
数据类型
有点迷,注意首字母大写???
- 有符号整数:Int
- 无符号整数:UInt
- 浮点:Double、Float
- 布尔值:Bool
- 字符:双引号 “a”
- 可选类型:使用可选类型(optionals)来处理值可能缺失的情况。可选类型表示有值或没有值。
没懂看后面
注意:swift3 中已经取消了++、–。
A += 1 // 类似 A++
区间运算符
闭区间运算符:1…5 区间值为 1, 2, 3, 4 和 5
半开区间运算符:1..< 5 区间值为 1, 2, 3, 和 4
for index in 1...5
类型别名
类型别名对当前的类型定义了另一个名字,类型别名通过使用 typealias 关键字来定义。
typealias newname = type
大概就是typedef
类型推断
let可作类型推断
类似void匹配各种数据但不是一个真的类型
var变量声明
var varB:Float
变量名也可以使用简单的 Unicode 字符
var 你好 = "你好世界" print(你好)
可选类型Optional
以下两种声明是相等的:
var optionalInteger: Int? var optionalInteger: Optional<Int>
在这两种情况下,变量 optionalInteger 都是可选整数类型
可选表示 ” 那儿有一个值,并且它等于 x ” 或者 ” 那儿没有值 ” 。
Optional 是一个含有两种情况的枚举,None 和 Some(T),用来表示可能有或可能没有值。
任何类型都可以明确声明为(或者隐式转换)可选类型。
当声明一个可选类型的时候,要确保 用括号给 ? 操作符一个合适的范围。例如,声明可选整数数组,应该写成 (Int[])?
如果可选类型T?包含类型为T的任何值(也就是说它的值是 Optional.Some(T) ),这个可选类型等于 true,反之为 false。
如果一个可选类型的实例包含一个值,你可以用后缀操作符 !来访问这个值
optionalInteger = 42 optionalInteger! // 42
!用在nil上会报运行错误,nil就是null吧
var myString:String? = nil if myString != nil { print(myString) }else{ print("字符串为 nil") }
强制解析
当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号(!)来获取值
-
import Cocoa
var myString:String?
myString = “Hello, Swift!”
if myString != nil { print(myString) }else{ print(“myString 值为 nil”) }
结果为
Optional("Hello, Swift!")
2.
import Cocoa var myString:String? myString = "Hello, Swift!" if myString != nil { // 强制解析 print( myString! ) }else{ print("myString 值为 nil") }
结果为
Hello, Swift!
自动解析
使用感叹号(!)替换问号(?)
import Cocoa var myString:String! myString = "Hello, Swift!" if myString != nil { print(myString) }else{ print("myString 值为 nil") }
结果为
Hello, Swift!
可选绑定
判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量
可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。
常量
let constantName = <initial value>
类型标注:
var constantName:<data type> = <optional initial value> let constB:Float = 3.14159
条件和循环
条件:
switch expression { case expression1 : statement(s) fallthrough /* 可选 */ case expression2, expression3 : statement(s) fallthrough /* 可选 */ default : /* 可选 */ statement(s); }
传统的for语句在swift3里弃用
但是现在用的4 = =
import Cocoa var someInts:[Int] = [10, 20, 30] for index in someInts { print( "index 的值为 \(index)") }
while循环就得多用点了
import Cocoa var index = 10 while index < 20 { print( "index 的值为 \(index)") index = index + 1 }
没有do……while,把do改成repeat
字符串
字符串变量可修改 ‘+=’
字符串插值
import Cocoa var varA = 20 let constA = 100 var varC:Float = 20.0 var stringA = "\(varA) 乘于 \(constA) 等于 \(varC * 100)" print( stringA )
字符串函数/运算符
函数/运算符 | 描述 |
---|---|
isEmpty | 判断字符串是否为空,返回布尔值 |
hasPrefix(prefix:String) | 检查字符串是否拥有特定前缀 |
hasSuffix(suffix: String) | 检查字符串是否拥有特定后缀。 |
Int(String) | 转换字符串数字为整型 |
String.characters.count | 字符串长度 |
utf8 | 可以通过遍历 String 的 utf8 属性来访问它的 UTF-8 编码 |
+ | 连接两个字符串,返回一个新的字符串 |
< | 判断两个字符串,对两个字符串的字符逐一比较 |
== | 判断两个字符串是否相等 |
字符串分割数组 – 基于空格
let fullName = "First Last" let fullNameArr = fullName.characters.split{$0 == " "}.map(String.init) // or simply: // let fullNameArr = fullName.characters.split{" "}.map(String.init) fullNameArr[0] // First fullNameArr[1] // Last
字符
遍历字符串中的字符
import Cocoa for ch in "Runoob".characters { print(ch) }
字符串连接字符
import Cocoa var varA:String = "Hello " let varB:Character = "G" varA.append( varB ) print("varC = \(varA)")
数组
创建
var someArray = [SomeType](repeating: InitialValue, count: NumbeOfElements) var someInts = [Int](repeating: 0, count: 3) var someInts:[Int] = [10, 20, 30]
使用 append() 方法或者赋值运算符 += 在数组末尾添加元素。
someInts.append(30) someInts += [40]
数组遍历
字符串数组
import Cocoa var someStrs = [String]() someStrs.append("Apple") someStrs.append("Amazon") someStrs.append("Runoob") someStrs += ["Google"] for item in someStrs { print(item) }
输出
Apple Amazon Runoob Google
如果我们同时需要每个数据项的值和索引值,可以使用 String 的 enumerate() 方法来进行数组遍历。
import Cocoa var someStrs = [String]() someStrs.append("Apple") someStrs.append("Amazon") someStrs.append("Runoob") someStrs += ["Google"] for (index, item) in someStrs.enumerated() { print("在 index = \(index) 位置上的值为 \(item)") }
可以使用加法操作符(+)来合并两种已存在的相同类型数组
数组名.count 数组元素个数 只读属性 isEmpty 来判断数组是否为空
字典
Swift 字典每个值(value)都关联唯一的键(key),键作为字典中的这个值数据的标识符。
大概就是Map类型?
创建字典
var someDict = [KeyType: ValueType]() var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
访问字典
var someVar = someDict[key]
返回的值是Optional类型。
添加 Key-Value 对
如果 key 不存在,则添加值,如果存在则修改 key 对应的值。
updateValue(_:forKey:)方法返回Optional值。
var oldVal = someDict.updateValue("One 新的值", forKey: 1)
移除 Key-Value 对
使用 removeValueForKey() 方法来移除字典 key-value 对。如果 key 存在该方法返回移除的值,如果不存在返回 nil 。
var removedValue = someDict.removeValue(forKey: 2)
遍历字典
for (key, value) in someDict { print("字典 key \(key) - 字典 value \(value)") }
字典转换为数组
let dictKeys = [Int](someDict.keys) let dictValues = [String](someDict.values) for (key) in dictKeys { print("\(key)") } for (value) in dictValues { print("\(value)") }
count属性表示键值对数量;isEmpty
函数
定义
-> 后定义函数的返回值类型。
func funcname(形参) -> returntype { Statement1 Statement2 …… Statement N return parameters }
不带参没有void,无返回值无->
调用
以下我们定义了一个函数名为 runoob 的函数,形参 site 的数据类型为 String,之后我们调用函数传递的实参也必须 String 类型,实参传入函数体后,将直接返回,返回的数据类型为 String。
func runoob(site: String) -> String { return (site) } print(runoob(site: "www.runoob.com"))
其实意思就是
String runoob(String site) { return site; } printf("%s",runoob("www.runoob.com"));//site变量值为"www.runoob.com"
这里的site是局部参数名,只能在函数内部使用。
函数参数都有一个外部参数名和一个局部参数名。
外部参数名实现传参。
import Cocoa func pow(firstArg a: Int, secondArg b: Int) -> Int { var res = a for _ in 1..<b { res = res * a } print(res) return res } pow(firstArg:5, secondArg:3)
a,b为局部参数名
另外两个长单词是外部参数名
如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。
可变参数通过在变量类型名后面加入(…)的方式来定义
func vari<N>(members: N...){ for i in members { print(i) } } vari(members: 4,3,5)
了解
可百度“泛型”
元组作为函数返回值 tuple
元组中的元素可以是任意类型,使用的是圆括号。
可以用元组(tuple)类型让多个值作为一个复合值从函数中返回。
func minMax(array: [Int]) -> (min: Int, max: Int) { var currentMin = array[0] var currentMax = array[0] for value in array[1..<array.count] { if value < currentMin { currentMin = value } else if value > currentMax { currentMax = value } } return (currentMin, currentMax) } let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) print("最小值为 \(bounds.min) ,最大值为 \(bounds.max)")
如果你不确定返回的元组一定不为nil,那么你可以返回一个可选的元组类型。
例如(Int, Int)?或(String, Int, Bool)?
常量,变量及 I/O 参数
就是C++中的引用符号&改成inout
func swapTwoInts(_ a: inout Int, _ b: inout Int) { let temporaryA = a a = b b = temporaryA } var x = 1 var y = 5 swapTwoInts(&x, &y)
_ 不知道干啥,是不是外部参数名
找了一些别的例子
func incrementor1(inout num: Int) { num += 1 } var b = 10 incrementor1(&b) b // 11
这两种写法应该都行,不过外部参数吗在函数调用的时候可以不写
指针UnsafePointer是不可变的,无法修改指针的值
函数类型
参数类型+返回类型
定义一个叫做 addition 的变量,参数与返回值类型均是 Int ,并让这个新变量指向 sum 函数:
func sum(a: Int, b: Int) -> Int { return a + b } var addition: (Int, Int) -> Int = sum
函数类型可作为参数类型、函数类型作为返回类型
函数嵌套
函数内定义一个新的函数,外部的函数可以调用函数内定义的函数。 这么刺激的嘛 但是好像就是在定义内部函数的位置就直接调用了它
闭包
就匿名函数
但它是一种引用类型,比如类和结构体也是引用类型,同样理解。
还有人说,可以把它作为一个引用类型的对象。可以把这个闭包的返回值(下面的返回值是一个函数)作为实例然后操作
func makeIncrementor(forIncrement amount: Int) -> () -> Int { var runningTotal = 0 func incrementor() -> Int { runningTotal += amount return runningTotal } return incrementor } let incrementByTen = makeIncrementor(forIncrement: 10) // 返回的值为10 incrementByTen() // 返回的值为20 incrementByTen() // 返回的值为30 incrementByTen() // 返回的值为40 incrementByTen() let alsoIncrementByTen = incrementByTen // 返回的值也为50 print(alsoIncrementByTen())
这种写法有点刺激哦
let studname = { print("Swift 闭包实例。") } studname()
输出结果为:
Swift 闭包实例。
接收两个参数并返回布尔值:
let divide = {(val1: Int, val2: Int) -> Int in return val1 / val2 } let result = divide(200, 20) print (result)
闭包表达式
sorted 方法
根据您提供的用于排序的闭包函数将已知类型数组中的值进行排序。 排序完成后,sorted(by:) 方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。
原数组不会被 sorted(by:) 方法修改。 两个参数:
- 已知类型的数组
-
闭包函数,传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明:如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回 true,反之返回 false。
import Cocoa let names = ["AT", "AE", "D", "S", "BE"] // 使用普通函数(或内嵌函数)提供排序功能,闭包函数类型需为(String, String) -> Bool。 func backwards(s1: String, s2: String) -> Bool { return s1 > s2 } var reversed = names.sorted(by: backwards) print(reversed)
输出:
["S", "D", "BE", "AT", "AE"]
“大于” 表示 “按照字母顺序较晚出现”
Swift 自动为内联函数提供了参数名称缩写功能。
通过$数字来顺序调用闭包的参数。
var reversed = names.sorted( by: { $0 > $1 } )
更简单的方式:
var reversed = names.sorted(by: >)
尾随闭包
var reversed = names.sorted() { $0 > $1 }
捕获值
就函数里定义的函数可以捕获其外部函数所有的参数以及定义的常量和变量。
枚举
- 它声明在类中,可以通过实例化类来访问它的值。
- 枚举也可以定义构造函数(initializers)来提供一个初始成员值;可以在原始的实现基础上扩展它们的功能。
- 可以遵守协议(protocols)来提供标准的功能。
// 定义枚举 enum DaysofaWeek { case Sunday case Monday case TUESDAY case WEDNESDAY case THURSDAY case FRIDAY case Saturday }
这些值是已经明确定义好的DaysofaWeek类型,不是01234。。了
一旦weekDay被声明为一个DaysofaWeek,你可以使用一个缩写语法(.)将其设置为另一个DaysofaWeek的值:
var weekDay = DaysofaWeek.THURSDAY var weekDay = .THURSDAY
相关值和原始值
相关值有不同数据类型
enum {10,0.8,"Hello"}
如
enum Student{ case Name(String) case Mark(Int,Int,Int) } var studDetails = Student.Name("Runoob") var studMarks = Student.Mark(98,97,95) switch studMarks { case .Name(let studName): print("学生的名字是: \(studName)。") case .Mark(let Mark1, let Mark2, let Mark3): print("学生的成绩是: \(Mark1),\(Mark2),\(Mark3)。") }
输出:
学生的成绩是: 98,97,95。
原始值数据类型相同,而且每个原始值在它的枚举声明中必须是唯一的。
在原始值为整数的枚举时,不需要显式的为每一个成员赋值,隐式赋值的值依次递增1。如果第一个值没有被赋初值,将会被自动置为0。
enum Month: Int { case January = 1, February, March, April, May, June, July, August, September, October, November, December } let yearMonth = Month.May.rawValue print("数字月份为: \(yearMonth)。")
5
结构体
跟C不一样的地方:
- 结构体不需要包含实现文件和接口。
-
结构体允许我们创建一个单一文件,且系统会自动生成面向其它代码的外部接口。
-
结构体总是通过被复制的方式在代码中传递,因此它的值是不可修改的。
这个文件这个词很迷哈,可以理解为java中的方法,然后自动生成方法的getter、setter就美滋滋了
定义:
struct MarkStruct{ var mark1: Int var mark2: Int var mark3: Int }
实例化:
let marks = studentMarks()
所以结构体居然不是变量???? 生气哦
以下实例化通过结构体实例化时传值并克隆一个结构体:
struct MarksStruct { var mark: Int init(mark: Int) { self.mark = mark } } var aStruct = MarksStruct(mark: 98) var bStruct = aStruct // aStruct 和 bStruct 是使用相同值的结构体! bStruct.mark = 97 print(aStruct.mark) // 98 print(bStruct.mark) // 97
this这个词改成了self
结构体的作用
使用时:
-
有理由预计一个结构体实例在赋值或传递时,封装的数据将会被拷贝而不是被引用。
-
任何在结构体中储存的值类型属性,也将会被拷贝,而不是被引用。
-
结构体不需要去继承另一个已存在类型的属性或者行为
结构体实例是通过值传递而不是通过引用传递。
这可真叫人伤心
不过它还有个类所以不懂结构体有存在的意义嘛?????不如枚举又不如类
类
与结构体相比新增了:
- 继承允许一个类继承另一个类的特征
- 类型转换允许在运行时检查和解释一个类实例的类型
- 解构器允许一个类实例释放任何其所被分配的资源
- 引用计数允许对一个类的多次引用
一句话就是类是引用类型了。
访问属性: 实例化类名.属性名
不能直接类名访问
恒等运算符
===:如果两个常量或者变量引用同一个类实例则返回 true
!==:引用不同类的实例
访问控制
internal
可以访问自己模块中源文件里的任何实体,但是别人不能访问该模块中源文件里的实体。
fileprivate
文件内私有,只能在当前源文件中使用。
private func someFunction() -> (SomeInternalClass, SomePrivateClass) { // 函数实现 }
大家都是private,函数前面也得写private
Setter的访问级别可以低于对应的Getter的访问级别