简单值
let
表示常量,var
表示变量,
不用声明类型,编译器自动判断。也可以在变量后面加冒号声明属性
也不用写分号。
var myVariable = 42
myVariable = 50
let myConstant = 42
let explicitDouble: Double = 70
将数强制转换为字符串:
let label = "aaa"
let width = 94
let widthStr = label+String(width)
print(widthStr)
//打印结果:aaa94
使用\()
也可以将值转为字符串:
let number1 = 3
let number2 = 5
let appleSum = "I have \(number1+number2) apples"
print(appleSum)
//打印结果:I have 8 apples
使用方括号[]
来创建数组和字典,最后一个元素后面允许有个逗号。
var lists = ["111", "222", "333"]
lists[0] = "444";
print(lists)
var dic = ["key1":"aaa", "key2":"bbb"]
dic["key3"] = "ccc";
print(dic)
//打印结果:
//["444", "222", "333"]
//["key2": "bbb", "key3": "ccc", "key1": "aaa"]
创建空数组和空字典,可以存基本类型.
var emptyArray = [Int]()
emptyArray = [124]
print(emptyArray)
var emptyDic = [String: Float]()
emptyDic = ["key" : 23]
print(emptyDic)
//打印结果:
//[124]
//["key": 23.0]
若信息可以推断出来,也可以这么初始化:
Lists = []
Dic = [:]
控制流
- if、switch、for、while等语句的括号都可以省掉:
let scores = [100, 99, 88, 50, 70]
var teamScore = 0
for obj in scores {
if obj>60 {
teamScore += 3
} else {
teamScore -= 1
}
}
if 后面必须是个布尔表达式,如
if score
会报错,不会默认和0对比。。使用
??
来提供一个默认值。如果可选值缺失的话,可以使用默认值来代替。
let aaa: String? = "aaa"
let bbb: String = "bbb"
let ccc = "hi \(aaa ?? bbb)"
print(ccc)
//若aaa不为空,打印hi aaa, 否则打印hi bbb
- switch的用法:不用写break。
let aaa: String = "abbb"
switch aaa {
case "aaa":
print("aaa")
case "bbb":
print("bbb")
case let x where x.hasSuffix("b"): // let 将匹配等式的值赋给常量 x
print("ccc");
default:
print("other")
}
- 使用 for-in 遍历字典和数组。(PS:
[]
既可以表示字典又可以表示数组)
let dic = [
"key1" : [1, 2, 3],
"key2" : [4, 5, 6]
]
for (key, arrs) in dic
{
for number in arrs {
print("结果是 \(number)")
}
}
- 在循环中使用
..<
来表示范围,相当于<
。而...
相当于<=
。
for i in 0..<4 { // 竟然不用声明 i 的类型
print(i)
}
//打印结果是 0 1 2 3
若换成 ... 则是打印 0 1 2 3 4
for i in 0...4 {
print(i)
}
//打印结果是 0 1 2 3 4
函数和闭包
-
func
声明函数,->
指定返回值类型 - 多个参数间用
,
号隔开
func getInfo(name: String, age: Int) ->String {
return "Info:\(name), \(age)"
}
print(getInfo(name: "laoyue", age: 12))
- 参数前面加
_
,调用时可以隐藏参数名。
func getInfo(_ name: String, _ age: Int) ->Void {
print("Info:\(name), \(age)")
}
getInfo("laoyue", 12)
- 使用元组来让一个函数返回多个值。该元组的元素可以用名称或数字来表示。
func abc(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var mi = scores[0]
var ma = scores[0]
var s = 0
for score in scores {
if score>ma {
ma = score
}
else if score<mi {
mi = score;
}
s += score
}
return (mi, ma, s)
}
- 不定参数的函数
func sum(scores: Int...) -> Void {
var sum: Int = 0;
for score in scores {
sum += score
}
print(sum)
}
sum(scores: 1, 2, 3, 4, 5)
- 函数内部可以嵌套另一个函数。被嵌套的函数可以访问外侧函数的变量, 你可以使用嵌套函数来重构一个太长或者太复杂的函数。
func printSumScore(scores: [Int]) -> Void {
var sumScore = 0;
func sum(scores: [Int])->Int {
for score in scores {
sumScore += score
}
return sumScore
}
print(sumScore);
}
- 函数是第一等类型,这意味着函数可以作为另一个函数的返回值。(没太看懂)
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
- 函数可以作为另一个函数的返回值。
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
//这里是将整个函数作为返回值返回,所以 makeIncrementer 函数的返回值是 `(Int) -> Int`,就是addOne函数的类型
}
var increment = makeIncrementer()
increment(7)
- 函数可以作为另一个函数的参数。conditon后面的参数类型是函数。
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)
- 闭包那块内容没看懂。。。
对象和类
- 创建一个类
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
- 创建一个类的实例,在类名后面加上括号。使用点语法来访问实例的属性和方法。
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
-
init
方法,self
用来区分属性和参数。
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
//此处若用 var 会警告,因为xcode未检测到 namedShape 有变化,认为其为常量
let namedShape = NamedShape(name: "laoyue")
- 用
override
覆写父类方法
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
- 属性的
setter
和getter
方法,必须同时实现,不能只实现其中的一个。
class EquilateralTriangle: NamedShape {//等边三角形
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength //1.设置子类声明的属性值
super.init(name: name) //2.调用父类的构造器
numberOfSides = 3 //3.改变父类定义的属性值。其他的工作比如调用方法、getters 和 setters 也可以在这个阶段完成。
}
var perimeter: Double {//周长属性,自己实现了getter、setter方法
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0 //该处的 newValue 就是传进来的值,是个隐性参数
}
}
override func simpleDescription() -> String {
return "An equilateral triangle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)
- 普通 getter 和 setter 方法,要定义两个属性。
class MyClass {
var _info: String = ""
var info: String {
get {
return _info
}
set {
_info = newValue //newValue为隐性参数
}
}
}
let mycalss = MyClass()
mycalss.info = "test";
print(mycalss.info);
- 若不需要重写 setter 和 getter方法,只是希望在赋值时执行某个任务,可以用
willSet
和didSet
,分别表示赋值前后。
class MyClass {
var _info: String?
var info: String? {
willSet {
print("willSet");
}
didSet {
print("didSet");
}
}
}
let mycalss = MyClass()
print("----------")
mycalss.info = "test";
print("----------")
//打印结果:
----------
willSet
didSet
----------
- 处理变量的可选值时,可以加
?
。方法也同样可以加。
let mycalss: MyClass? = MyClass()
let myname = mycalss?.name //意思是若 mycalss 为空,则后面的就不执行了,整个返回为空。若不为空才执行
枚举和结构体
- 枚举里可以添加方法
enum Rank: Int {
case ace = 1
case jack, queen, king
func simpleDes() -> String {
switch self {
case .ace:
return "ace"
case .jack:
return "jack"
case .queen:
return "queen"
default:
return String(self.rawValue)
}
}
}
let jackRawValue = Rank.jack.rawValue
print("\(jackRawValue), \(Rank.jack)") //直接打印是字符串,打印rawValue才是Int类型的值
//打印结果:
2, jack
enum Suit {
case spades, hearts, diamonds, clubs
func simpleDescription() -> String {
switch self {
case .spades:
return "spades"
case .hearts:
return "hearts"
case .diamonds:
return "diamonds"
case .clubs:
return "clubs"
}
}
}
let hearts = Suit.hearts
let heartsDescription = hearts.simpleDescription()
注意在上面的例子中用了两种方式引用 hearts 枚举成员:给 hearts 常量赋值时,枚举成员 Suit.hearts 需要用全名来引用,因为常量没有显式指定类型。在 switch 里,枚举成员使用缩写 .hearts 来引用,因为 self 已经是一个 suit 类型,在已知变量类型的情况下可以使用缩写。
如果枚举成员的实例有原始值,那么这些值是在声明的时候就已经决定了,这意味着不同的枚举成员总会有一个相同的原始值。当然我们也可以为枚举成员设定关联值,关联值是在创建实例时决定的。这意味着不同的枚举成员的关联值都可以不同。你可以把关联值想象成枚举成员的寄存属性。例如,考虑从服务器获取日出和日落的时间。服务器会返回正常结果或者错误信息。
enum ServerResponse {
case result(String, String)
case failure(String)
}
let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")
switch success {
case let .result(sunrise, sunset):
print("Sunrise is at \(sunrise) and sunset is at \(sunset)")
case let .failure(message):
print("Failure... \(message)")
}
注意日升和日落时间是如何从 ServerResponse 中提取到并与 switch 的 case 相匹配的。
结构体。结构体和类有很多相同的地方,比如方法和构造器。它们之间最大的一个区别就是结构体是传值,类是传引用。
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .three, suit: .spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
协议和扩展
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 关键字用来标记一个会修改结构体的方法。SimpleClass 的声明不需要标记任何方法,因为类中的方法通常可以修改类属性(类的性质)。
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
- 下面是给
Int
类型增加扩展,可增加新的方法和属性。
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
print(7.simpleDescription)
- 你可以像使用其他命名类型一样使用协议名——例如,创建一个有不同类型但是都实现一个协议的对象集合。当你处理类型是协议的值时,协议外定义的方法不可用。
let protocolValue: ExampleProtocol = a
print(protocolValue.simpleDescription)
// print(protocolValue.anotherProperty) // 去掉注释可以看到错误
- 即使 protocolValue 变量运行时的类型是 simpleClass ,编译器还是会把它的类型当做ExampleProtocol。这表示你不能调用在协议之外的方法或者属性。