Swift语法1

目录

Swif   数据类型  变量   可选类型  强制解析  自动解析   常量
类型标注   字面量  字符串  字符(Character)    数组     字典
函数  流程    guard   switch  闭包   枚举  类  属性    方法

Swift

1.类型安全
Swift 是一个类型安全(type safe)的语言。
由于 Swift 是类型安全的,所以它会在编译你 的代码时进行类型检查(type checks),并把不匹配的类型标记为错误。这可以让你在开发的时候尽早发现并修复错误。

2.类型别名
类型别名对当前的类型定义了另一个名字,类型别名通过使用 typealias 关键字来定义。语法格式如下:

typealias newname = type

例如以下定义了 Int 的类型别名为 Feet:

typealias Feet = Int

现在,我们可以通过别名来定义变量:

import Cocoa
typealias Feet = Int
var distance: Feet = 100
print(distance)

3.类型推断
当你要处理不同类型的值时,类型检查可以帮你避免错误。然而,这并不是说你每次声明常量和变量的时候都需要显式指定类型。
如果你没有显式指定类型,Swift 会使用类型推断(type inference)来选择合适的类型。
例如,如果你给一个新常量赋值42并且没有标明类型,Swift 可以推断出常量类型是Int,因为你给它赋的初始值看起来像一个整数:

let meaningOfLife = 42
// meaningOfLife 会被推测为 Int 类型

数据类型

1.基本数据类型有:整型:Int, 浮点型:Float, 双精度浮点型:Double, 字符型:Character, 字符串型:String
定义常量:var x: Float = 42.0
定义变量:let y: Int = 12

注意:Swift可以推断出数据的类型,所以在变量常量声明的时候可以省略数据类型。

var x = 12
let y = 42.0

2.字符串的声明:

let name : String = "綦帅鹏"
let age : Int = 10
print("My name is " + name + "," + String(age) + " years old!")
print("My name is \(name), \(age) years old!")

注意:
Swift中字符串可以通过"+"来拼接。
在Swift字符串中可以通过"(名称)"来获取常量、变量的值。

3.元组:元组是一系列不同类型数据的有序集合,可以包含不同的数据类型,通过".下标"来获取对应的数据。

//元组

let student = ("綦帅鹏", 27, "打球")
print("学生:\(student.0), \(student.1)岁,喜欢\(student.2)!")

4.数组:数组是一系列相同类型的数据的有序集合,数组中的数据类型必须相同。

//数组,数组中数据的类型必须相同
var studentsName = ["张三", "李四", "王五"]
//添加数据
studentsName.append("赵六")
print(studentsName)
//添加多个数据,也可以理解为数组合并
studentsName += ["綦帅鹏", "綦朝晖"]
print(studentsName)
//添加数据到指定位置
studentsName.insert("廖腾逸", at: 0)
print(studentsName)
//修改数据
studentsName[1] = "廖雨琦"
print(studentsName)
//移除数据
studentsName.remove(at: 2)
print(studentsName)
//移除最后一个数据
studentsName.removeLast()
print(studentsName)
print(studentsName)
//移除所有数据
studentsName.removeAll()
print(studentsName)

5.字典:字典是一系列相同类型的数据的无序集合,数据是由键值对存在的,并且键不能为nil。

//字典:不能将key指定为nil
var product = ["name":"iPhone5", "size":"4寸"]
print(product)
//取值
print(product["name"]!)
//添加数据
product["address"] = "香港"
print(product)
//修改数据
product["size"] = "4英寸"
print(product)
//删除数据
product["address"] = nil
print(product)

//字典数组搭配

print([[1, 2, 3], ["1", "2", "3"]])
print([["name": "张三", "address": "湖南"], ["name": "李四", "address": "北京"]])
//空数组
var arr: Array<Int> = []
arr.append(1)
print(arr)
var otherArr = [Int]()
otherArr += [2]
print(otherArr)
//空字典
var dic = Dictionary<String, String>()
dic["name"] = "张三"
print(dic)

6.数组与字典的遍历

//数组遍历
for item in [1, 2, 3] {
    print(item)
}
for (index, item) in [1, 2, 3].enumerated() {
    print("\(index): \(item)")
}
//遍历字典
for (key, value) in ["name": "张三", "address": "湖南"] {
    print("\(key):\(value)")
}

变量

变量是一种使用方便的占位符,用于引用计算机内存地址。
Swift 每个变量都指定了特定的类型,该类型决定了变量占用内存的大小,不同的数据类型也决定可存储值的范围。

1.变量声明
变量声明意思是告诉编译器在内存中的哪个位置上为变量创建多大的存储空间。
在使用变量前,你需要使用 var 关键字声明它,如下所示:

var variableName = <initial value>

2.变量命名
变量名可以由字母,数字和下划线组成。
变量名需要以字母或下划线开始。
Swift 是一个区分大小写的语言,所以字母大写与小写是不一样的。
3.变量输出
变量和常量可以使用 print(swift 2 将 print 替换了 println) 函数来输出。
在字符串中可以使用括号与反斜线来插入变量,如下实例:

import Cocoa
var name = "菜鸟教程"
var site = "http://www.runoob.com"
print("\(name)的官网地址为:\(site)")

Swift 可选(Optionals)类型

Swift 的可选(Optional)类型,用于处理值缺失的情况。可选表示"那儿有一个值,并且它等于 x "或者"那儿没有值"。
Swfit语言定义后缀?作为命名类型Optional的简写,换句话说,以下两种声明是相等的:

var optionalInteger: Int?
var optionalInteger: Optional<Int>

在这两种情况下,变量 optionalInteger 都是可选整数类型。注意,在类型和 ?之间没有空格。
Optional 是一个含有两种情况的枚举,None 和 Some(T),用来表示可能有或可能没有值。任何类型都可以明确声明为(或者隐式转换)可选类型。当声明一个可选类型的时候,要确保用括号给 ? 操作符一个合适的范围。例如,声明可选整数数组,应该写成 (Int[])? 写成 Int[]? 会报错。
当你声明一个可选变量或者可选属性的时候没有提供初始值,它的值会默认为 nil。
可选项遵照 LogicValue 协议,因此可以出现在布尔环境中。在这种情况下,如果可选类型T?包含类型为T的任何值(也就是说它的值是 Optional.Some(T) ),这个可选类型等于 true,反之为 false。
如果一个可选类型的实例包含一个值,你可以用后缀操作符 !来访问这个值,如下所示:

optionalInteger = 42
optionalInteger! // 42

使用操作符!去获取值为nil的可选变量会有运行时错误。
你可以用可选链接和可选绑定选择性执行可选表达式上的操作。如果值为nil,任何操作都不会执行,也不会有运行报错。

注意:可选类型类似于Objective-C中指针的nil值,但是nil只对类(class)有用,而可选类型对所有的类型都可用,并且更安全。

强制解析

当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号(!)来获取值。这个感叹号表示"我知道这个可选有值,请使用它。"这被称为可选值的强制解析(forced unwrapping)。
实例如下:

import Cocoa
var myString:String?
myString = "Hello, Swift!"
if myString != nil {
   print(myString)
}else{
   print("myString 值为 nil")
}
以上程序执行结果为:
Optional("Hello, Swift!")

强制解析可选值,使用感叹号(!):

import Cocoa
var myString:String?
myString = "Hello, Swift!"
if myString != nil {
   // 强制解析
   print( myString! )
}else{
   print("myString 值为 nil")
}
以上程序执行结果为:
Hello, Swift!

注意:使用!来获取一个不存在的可选值会导致运行时错误。使用!来强制解析值之前,一定要确定可选包含一个非nil的值。

自动解析

你可以在声明可选变量时使用感叹号(!)替换问号(?)。这样可选变量在使用时就不需要再加一个感叹号(!)来获取值,它会自动解析。
实例如下:

import Cocoa
var myString:String!
myString = "Hello, Swift!"
if myString != nil {
   print(myString)
}else{
   print("myString 值为 nil")
}
以上程序执行结果为:
Hello, Swift!

可选绑定

使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。
像下面这样在if语句中写一个可选绑定:

if let constantName = someOptional {
    statements
}

让我们来看下一个简单的可选绑定实例:

import Cocoa
var myString:String?
myString = "Hello, Swift!"
if let yourString = myString {
   print("你的字符串值为 - \(yourString)")
}else{
   print("你的字符串没有值")
}
以上程序执行结果为:
你的字符串值为 - Hello, Swift!

Swift 常量

常量一旦设定,在程序运行时就无法改变其值。
常量可以是任何的数据类型如:整型常量,浮点型常量,字符常量或字符串常量。同样也有枚举类型的常量:
常量类似于变量,区别在于常量的值一旦设定就不能改变,而变量的值可以随意更改。
常量声明
常量使用关键字 let 来声明,语法如下:

let constantName = <initial value>

以下是一个简单的 Swift 程序中使用常量的实例:

import Cocoa
let constA = 42
print(constA)

1.常量命名
常量的命名可以由字母,数字和下划线组成。
常量需要以字母或下划线开始。
Swift 是一个区分大小写的语言,所以字母大写与小写是不一样的。
常量名也可以使用简单的 Unicode 字符;
2.常量输出
变量和常量可以使用 print(swift 2 将 print 替换了 println) 函数来输出。
在字符串中可以使用括号与反斜线来插入常量

类型标注

当你声明常量或者变量的时候可以加上类型标注(type annotation),说明常量或者变量中要存储的值的类型。如果要添加类型标注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称。

var constantName:<data type> = <optional initial value>

以下是一个简单是实例演示了 Swift 中常量使用类型标注。需要注意的是常量定义时必须初始值:

import Cocoa
let constA = 42
print(constA)
let constB:Float = 3.14159
print(constB)

Swift 字面量

所谓字面量,就是指像特定的数字,字符串或者是布尔值这样,能够直接了当地指出自己的类型并为变量进行赋值的值。比如在下面:

let aNumber = 3         //整型字面量
let aString = "Hello"   //字符串字面量
let aBool = true        //布尔值字面量

1.布尔型字面量
布尔型字面量的默认类型是 Bool。
布尔值字面量有三个值,它们是 Swift 的保留关键字:

true 表示真。
false 表示假。
nil 表示没有值。

2.字符串型字面量
字符串型字面量由被包在双引号中的一串字符组成,形式如下:

"characters"

字符串型字面量中不能包含未转义的双引号 (")、未转义的反斜线(\)、回车符或换行符。

\0  空字符
\\  反斜线 \
\b  退格(BS) ,将当前位置移到前一列
\f  换页(FF),将当前位置移到下页开头
\n  换行符
\r  回车符
\t  水平制表符
\v  垂直制表符
\'  单引号
\"  双引号
\000    1到3位八进制数所代表的任意字符
\xhh... 1到2位十六进制所代表的任意字符

字符串

1.创建字符串
你可以通过使用字符串字面量或 String 类的实例来创建一个字符串:

// 使用字符串字面量
var stringA = "Hello, World!"
print( stringA )

// String 实例化
var stringB = String("Hello, World!")
print( stringB )

2.空字符串
你可以使用空的字符串字面量赋值给变量或初始化一个String类的实例来初始值一个空的字符串。 我们可以使用字符串属性 isEmpty 来判断字符串是否为空:

// 使用字符串字面量创建空字符串
var stringA = ""
if stringA.isEmpty {
   print( "stringA 是空的" )
} else {
   print( "stringA 不是空的" )
}

// 实例化 String 类来创建空字符串
let stringB = String()
if stringB.isEmpty {
   print( "stringB 是空的" )
} else {
   print( "stringB 不是空的" )
}

3.字符串常量
你可以将一个字符串赋值给一个变量或常量,变量是可修改的,常量是不可修改的。

// stringA 可被修改
var stringA = "菜鸟教程:"
stringA += "http://www.runoob.com"
print( stringA )

// stringB 不能修改
let stringB = String("菜鸟教程:")
stringB += "http://www.runoob.com"
print( stringB )
以上程序执行输出结果会报错,以为 stringB 为常量是不能被修改的

4.字符串中插入值
字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。 您插入的字符串字面量的每一项都在以反斜线为前缀的圆括号中:

var varA   = 20
let constA = 100
var varC:Float = 20.0
var stringA = "\(varA) 乘于 \(constA) 等于 \(varC * 100)"
print( stringA )
以上程序执行输出结果为:
20 乘于 100 等于 2000.0

5.字符串连接
字符串可以通过 + 号来连接,实例如下:

let constA = "菜鸟教程:"
let constB = "http://www.runoob.com"
var stringA = constA + constB
print( stringA )

6.字符串长度
字符串长度使用 String.characters.count 属性来计算,实例如下:

var varA   = "www.runoob.com"
print( "\(varA), 长度为 \(varA.characters.count)" )
以上程序执行输出结果为:
www.runoob.com, 长度为 14

7.字符串比较
你可以使用 == 来比较两个字符串是否相等:

var varA   = "Hello, Swift!"
var varB   = "Hello, World!"
if varA == varB {
   print( "\(varA) 与 \(varB) 是相等的" )
} else {
   print( "\(varA) 与 \(varB) 是不相等的" )
}
以上程序执行输出结果为:
Hello, Swift! 与 Hello, World! 是不相等的

8.Unicode 字符串
Unicode 是一个国际标准,用于文本的编码,Swift 的 String 类型是基于 Unicode建立的。你可以循环迭代出字符串中 UTF-8 与 UTF-16 的编码,实例如下:

var unicodeString   = "菜鸟教程"
print("UTF-8 编码: ")
for code in unicodeString.utf8 {
   print("\(code) ")
}
print("\n")
print("UTF-16 编码: ")
for code in unicodeString.utf16 {
   print("\(code) ")
}

9.字符串函数及运算符

  • isEmpty 判断字符串是否为空,返回布尔值
  • hasPrefix(prefix: String) 检查字符串是否拥有特定前缀
  • hasSuffix(suffix: String) 检查字符串是否拥有特定后缀。
  • Int(String) 转换字符串数字为整型。 实例:
let myString: String = "256"
let myInt: Int? = Int(myString)
  • String.characters.count 计算字符串的长度
  • < 比较两个字符串,对两个字符串的字母逐一比较。
  • += 连接操作符两边的字符串并将新字符串赋值给左边的操作符变量
    • 连接两个字符串,并返回一个新的字符串
  • == 判断两个字符串是否相等

Swift 字符(Character)

Swift 的字符是一个单一的字符字符串字面量,数据类型为 Character。
以下实例列出了两个字符实例:

let char1: Character = "A"
  • 如果你想在 Character(字符) 类型的常量中存储更多的字符,则程序执行会报错,如下所示:
// Swift 中以下赋值会报错
let char: Character = "AB"
  • Swift 中不能创建空的 Character(字符) 类型变量或常量:
// Swift 中以下赋值会报错
let char1: Character = ""
  • 遍历字符串中的字符
    Swift 的 String 类型表示特定序列的 Character(字符) 类型值的集合。 每一个字符值代表一个 Unicode 字符。
    您可通过for-in循环来遍历字符串中的characters属性来获取每一个字符的值:
for ch in "Runoob".characters {
    print(ch)
}
  • 字符串连接字符
    以下实例演示了使用 String 的 append() 方法来实现字符串连接字符:
var varA:String = "Hello "
let varB:Character = "G"
varA.append( varB )
print("varC  =  \(varA)")
以上程序执行输出结果为:
varC  =  Hello G

Swift 数组

Swift 数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中。
Swift 数组会强制检测元素的类型,如果类型不同则会报错,Swift 数组应该遵循像Array<Element>这样的形式,其中Element是这个数组中唯一允许存在的数据类型。
如果创建一个数组,并赋值给一个变量,则创建的集合就是可以修改的。这意味着在创建数组后,可以通过添加、删除、修改的方式改变数组里的项目。如果将一个数组赋值给常量,数组就不可更改,并且数组的大小和内容都不可以修改。
1.创建数组
我们可以使用构造语法来创建一个由特定数据类型构成的空数组:

var someArray = [SomeType]()

以下是创建一个初始化大小数组的语法:

var someArray = [SomeType](repeating: InitialValue, count: NumbeOfElements)

以下实例创建了一个类型为 Int ,数量为 3,初始值为 0 的空数组:

var someInts = [Int](repeating: 0, count: 3)

以下实例创建了含有三个元素的数组:

var someInts:[Int] = [10, 20, 30]

2.访问数组
我们可以根据数组的索引来访问数组的元素,语法如下:

var someVar = someArray[index]

index 索引从 0 开始,及索引 0 对应第一个元素,索引 1 对应第二个元素,以此类推。
我们可以通过以下实例来学习如何创建,初始化,访问数组:

var someInts = [Int](repeating: 10, count: 3)
var someVar = someInts[0]
print( "第一个元素的值 \(someVar)" )

3.修改数组
你可以使用 append() 方法或者赋值运算符 += 在数组末尾添加元素,如下所示,我们初始化一个数组,并向其添加元素,也可以通过索引修改数组元素的值:

var someInts = [Int]()
someInts.append(20)
someInts.append(30)
someInts += [40]
var someVar = someInts[0]
print( "第一个元素的值 \(someVar)" )
print( "第二个元素的值 \(someInts[1])" )
print( "第三个元素的值 \(someInts[2])" )

// 修改最后一个元素
someInts[2] = 50
print( "第三个元素的值 \(someInts[2])" )

以上程序执行输出结果为:
第一个元素的值 20
第二个元素的值 30
第三个元素的值 40
第三个元素的值 50

4.遍历数组

  • 使用for-in循环来遍历所有数组中的数据项:
var someStrs = [String]()
someStrs.append("Apple")
someStrs.append("Amazon")
someStrs.append("Runoob")
someStrs += ["Google"]

for item in someStrs {
   print(item)
}
  • 如果我们同时需要每个数据项的值和索引值,可以使用 String 的 enumerate() 方法来进行数组遍历。实例如下:
var someStrs = [String]()
someStrs.append("Apple")
someStrs.append("Amazon")
someStrs.append("Runoob")
someStrs += ["Google"]

for (index, item) in someStrs.enumerated() {
    print("在 index = \(index) 位置上的值为 \(item)")
}
以上程序执行输出结果为:
在 index = 0 位置上的值为 Apple
在 index = 1 位置上的值为 Amazon
在 index = 2 位置上的值为 Runoob
在 index = 3 位置上的值为 Google

5.合并数组
我们可以使用加法操作符(+)来合并两种已存在的相同类型数组。新数组的数据类型会从两个数组的数据类型中推断出来:

var intsA = [Int](repeating: 2, count:2)
var intsB = [Int](repeating: 1, count:3)
var intsC = intsA + intsB
for item in intsC {
    print(item)
}

6.count 属性
使用 count 属性来计算数组元素个数:

var intsB = [Int](count:3, repeatedValue: 1)
print("intsB 元素个数为 \(intsB.count)")

7.isEmpty 属性
我们可以通过只读属性 isEmpty 来判断数组是否为空,返回布尔值:

var intsA = [Int](count:2, repeatedValue: 2)
var intsB = [Int](count:3, repeatedValue: 1)
var intsC = [Int]()
print("intsA.isEmpty = \(intsA.isEmpty)")
print("intsB.isEmpty = \(intsB.isEmpty)")
print("intsC.isEmpty = \(intsC.isEmpty)")
以上程序执行输出结果为:
intsA.isEmpty = false
intsB.isEmpty = false
intsC.isEmpty = true

字典

Swift 字典用来存储无序的相同类型数据的集合,Swift 字典会强制检测元素的类型,如果类型不同则会报错。
Swift 字典每个值(value)都关联唯一的键(key),键作为字典中的这个值数据的标识符。
和数组中的数据项不同,字典中的数据项并没有具体顺序。我们在需要通过标识符(键)访问数据的时候使用字典,这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。
Swift 字典的key没有类型限制可以是整型或字符串,但必须是唯一的。
如果创建一个字典,并赋值给一个变量,则创建的字典就是可以修改的。这意味着在创建字典后,可以通过添加、删除、修改的方式改变字典里的项目。如果将一个字典赋值给常量,字典就不可修改,并且字典的大小和内容都不可以修改。

1.创建字典
我们可以使用以下语法来创建一个特定类型的空字典:

var someDict =  [KeyType: ValueType]()

以下是创建一个空字典,键的类型为 Int,值的类型为 String 的简单语法:

var someDict = [Int: String]()

以下为创建一个字典的实例:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]

2.访问字典
我们可以根据字典的索引来访问数组的元素,语法如下:

var someVar = someDict[key]

我们可以通过以下实例来学习如何创建,初始化,访问字典:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var someVar = someDict[1]

3.修改字典
我们可以使用 updateValue(forKey:) 增加或更新字典的内容。如果 key 不存在,则添加值,如果存在则修改 key 对应的值。updateValue(_:forKey:)方法返回Optional值。实例如下:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var oldVal = someDict.updateValue("One 新的值", forKey: 1)
var someVar = someDict[1]

4.移除 Key-Value 对
使用 removeValueForKey() 方法来移除字典 key-value 对。如果 key 存在该方法返回移除的值,如果不存在返回 nil 。实例如下:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var removedValue = someDict.removeValue(forKey: 2)

5.遍历字典

  • 可以使用 for-in 循环来遍历某个字典中的键值对。实例如下:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
for (key, value) in someDict {
   print("字典 key \(key) -  字典 value \(value)")
}
  • 可以使用enumerate()方法来进行字典遍历,返回的是字典的索引及 (key, value) 对,实例如下:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
for (key, value) in someDict.enumerate() {
    print("字典 key \(key) -  字典 (key, value) 对 \(value)")
}

6.字典转换为数组
你可以提取字典的键值(key-value)对,并转换为独立的数组。实例如下:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
let dictKeys = [Int](someDict.keys)
let dictValues = [String](someDict.values)

print("输出字典的键(key)")
for (key) in dictKeys {
    print("\(key)")
}
print("输出字典的值(value)")
for (value) in dictValues {
    print("\(value)")
}

7.count 属性
可以使用只读的 count 属性来计算字典有多少个键值对:

var someDict1:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
print("someDict1 含有 \(someDict1.count) 个键值对")

8.isEmpty 属性
Y我们可以通过只读属性 isEmpty 来判断字典是否为空,返回布尔值:

var someDict1:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
print("someDict1 = \(someDict1.isEmpty)")

函数

Swift 函数用来完成特定任务的独立的代码块。
Swift使用一个统一的语法来表示简单的C语言风格的函数到复杂的Objective-C语言风格的方法。
函数声明: 告诉编译器函数的名字,返回类型及参数。
函数定义: 提供了函数的实体。
Swift 函数包含了参数类型及返回值类型;

1.函数定义
Swift 定义函数使用关键字 func。
定义函数的时候,可以指定一个或多个输入参数和一个返回值类型。
每个函数都有一个函数名来描述它的功能。通过函数名以及对应类型的参数值来调用这个函数。函数的参数传递的顺序必须与参数列表相同。
函数的实参传递的顺序必须与形参列表相同,-> 后定义函数的返回值类型。
语法

func funcname(形参) -> returntype
{
   Statement1
   Statement2
   ……
   Statement N
   return parameters
}

以下我们定义了一个函数名为 runoob 的函数,形参的数据类型为 String,返回值也为 String:

func runoob(site: String) -> String {
    return (site)
}
print(runoob(site: "www.runoob.com"))
以上程序执行输出结果为:
www.runoob.com

2.函数调用
可以通过函数名以及对应类型的参数值来调用函数,函数的参数传递的顺序必须与参数列表相同。
3.函数参数
函数可以接受一个或者多个参数,这些参数被包含在函数的括号之中,以逗号分隔。
以下实例向函数 runoob 传递站点名 name 和站点地址 site:

func runoob(name: String, site: String) -> String {
    return name + site
}
print(runoob(name: "菜鸟教程:", site: "www.runoob.com"))
以上程序执行输出结果为:
菜鸟教程:www.runoob.com

4.不带参数函数
我们可以创建不带参数的函数。
语法:

func funcname() -> datatype {
   return datatype
}

实例

func sitename() -> String {
    return "菜鸟教程"
}
print(sitename())
以上程序执行输出结果为:
菜鸟教程

5.元组作为函数返回值
函数返回值类型可以是字符串,整型,浮点型等。
元组与数组类似,不同的是,元组中的元素可以是任意类型,使用的是圆括号。
你可以用元组(tuple)类型让多个值作为一个复合值从函数中返回。
如果你不确定返回的元组一定不为nil,那么你可以返回一个可选的元组类型。
你可以通过在元组类型的右括号后放置一个问号来定义一个可选元组,例如(Int, Int)?或(String, Int, Bool)?

注意:
可选元组类型如(Int, Int)?与元组包含可选类型如(Int?, Int?)是不同的.可选的元组类型,整个元组是可选的,而不只是元组中的每个元素值。

前面的minMax(:)函数返回了一个包含两个Int值的元组。但是函数不会对传入的数组执行任何安全检查,如果array参数是一个空数组,如上定义的minMax(:)在试图访问array[0]时会触发一个运行时错误。
为了安全地处理这个"空数组"问题,将minMax(_:)函数改写为使用可选元组返回类型,并且当数组为空时返回nil:

func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.isEmpty { return nil }
    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)
}
if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
    print("最小值为 \(bounds.min),组大值为 \(bounds.max)")
}
以上程序执行输出结果为:
最小值为 -6,组大值为 109

6.没有返回值函数
下面是 runoob(_:) 函数的另一个版本,这个函数接收菜鸟教程官网网址参数,没有指定返回值类型,并直接输出 String 值,而不是返回它:

func runoob(site: String) {
    print("菜鸟教程官网:\(site)")
}
runoob(site: "http://www.runoob.com")
以上程序执行输出结果为:
菜鸟教程官网:http://www.runoob.com

7.函数参数名称
函数参数都有一个外部参数名和一个局部参数名。

  • 局部参数名
    局部参数名在函数的实现内部使用。
func sample(number: Int) {
   println(number)
}

以上实例中 number 为局部参数名,只能在函数体内使用。

  • 外部参数名
    你可以在局部参数名前指定外部参数名,中间以空格分隔,外部参数名用于在函数调用时传递给函数的参数。
    如下你可以定义以下两个函数参数名并调用它:
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)
以上程序执行输出结果为:
125

注意: 如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。

8.可变参数
可变参数可以接受零个或多个值。函数调用时,你可以用可变参数来指定函数参数,其数量是不确定的。
可变参数通过在变量类型名后面加入(...)的方式来定义。

func vari<N>(members: N...){
    for i in members {
        print(i)
    }
}
vari(members: 4,3,5)
vari(members: 4.5, 3.1, 5.6)

9.常量,变量及 I/O 参数
一般默认在函数中定义的参数都是常量参数,也就是这个参数你只可以查询使用,不能改变它的值。
如果想要声明一个变量参数,可以在参数定义前加 inout 关键字,这样就可以改变这个参数的值了。
例如:

func  getName(_ name: inout String).........

此时这个 name 值可以在函数中改变。
一般默认的参数传递都是传值调用的,而不是传引用。所以传入的参数在函数内改变,并不影响原来的那个参数。传入的只是这个参数的副本。
当传入的参数作为输入输出参数时,需要在参数名前加 & 符,表示这个值可以被函数修改。
实例

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}
var x = 1
var y = 5
swapTwoInts(&x, &y)
print("x 现在的值 \(x), y 现在的值 \(y)")
swapTwoInts(_:_:) 函数简单地交换 a 与 b 的值。该函数先将 a 的值存到一个临时常量 temporaryA 中,然后将 b 的值赋给 a,最后将 temporaryA 赋值给 b。
需要注意的是,someInt 和 anotherInt 在传入 swapTwoInts(_:_:) 函数前,都加了 & 的前缀。
以上程序执行输出结果为:
x 现在的值 5, y 现在的值 1

10.函数类型及使用
每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成。

func inputs(no1: Int, no2: Int) -> Int {
   return no1/no2
}
  • 函数也可以定义一个没有参数,也没有返回值的函数,如下所示:
func inputstr() {
   print("菜鸟教程")
   print("www.runoob.com")
}
inputstr()
以上程序执行输出结果为:
菜鸟教程
www.runoob.com
  • 函数类型作为参数类型、函数类型作为返回类型
    我们可以将函数作为参数传递给另外一个参数:
func sum(a: Int, b: Int) -> Int {
    return a + b
}
var addition: (Int, Int) -> Int = sum
print("输出结果: \(addition(40, 89))")
func another(addition: (Int, Int) -> Int, a: Int, b: Int) {
    print("输出结果: \(addition(a, b))")
}
another(addition: sum, a: 10, b: 20)
以上程序执行输出结果为:
输出结果: 129
输出结果: 30
  • 函数嵌套
    函数嵌套指的是函数内定义一个新的函数,外部的函数可以调用函数内定义的函数。
    实例如下:
func calcDecrement(forDecrement total: Int) -> () -> Int {
   var overallDecrement = 0
   func decrementer() -> Int {
      overallDecrement -= total
      return overallDecrement
   }
   return decrementer
}
let decrem = calcDecrement(forDecrement: 30)
print(decrem())
以上程序执行输出结果为:
-30

inputs 函数类型有两个 Int 型的参数(no1、no2)并返回一个 Int 型的值。

流程控制

1.for循环

let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for num in arr {
    print(num)
}
for item in 1...10 {
    print(item)
}
for item in 1..<10 {
    print(item)
}
for item in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].reversed() {
    print(item)
}

2.if…else…选择

let lightColor = "red"
if lightColor == "red"
{
    print("Stop!")
}
else
{
    print("Go!")
}

3.while循环和switch…case…选择

let limit = 75
var speed = 0
while speed < 100 {
    speed += 1
    switch speed {
    case 0..<20:
        print("太慢啦!")
    case 20..<40:
        print("快点行吗!")
    case 40..<60:
        print("速度起来啦!")
    case 60...limit:
        print("别超速呀,我的哥!")
    default:
        print("超速啦,我的哥!")
    }
    if speed > limit {
        break
    }
}
  • 注意:在Swift中可以不需要使用break关键字
    在Swift的判断句中必须有明确的真假
    不再有非0即真
    必须有明确的Bool值
    Bool有两个取值:false/true

  • 控制语句 描述

    • continue 语句 :告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。
    • break 语句 :中断当前循环。
    • fallthrough 语句 :如果在一个case执行完后,继续执行下面的case,需要使用fallthrough(贯穿)关键字。

guard的使用

guard是Swift2.0新增的语法
它与if语句非常类似,它设计的目的是提高程序的可读性
guard语句必须带有else语句,它的语法如下:

当条件表达式为true时候跳过else语句中的内容,执行语句组内容

  guard 条件表达式 else {
      // 条换语句
      break
  }
  语句组

例子

    var age = 18
    func online(age : Int) -> Void {
        guard age >= 18 else {
            print("回家去")
            return
        }
        print("可以上网")
    }
    online(age)

switch

Switch作为选择结构中必不可少的语句也被加入到了Swift中
只要有过编程经验的人对Switch语句都不会感到陌生
但苹果对Switch进行了大大的增强,使其拥有其他语言中没有的特性
switch的简单使用
基本用法和OC用法一致
不同之处:
switch后可以不跟()
case后可以不跟break(默认会有break)
例子:

    let sex = 0
    switch sex {
    case 0 :
        print("男")
    case 1 :
        print("女")
    default :
        print("其他")
    }

简单使用补充:
一个case判断中,可以判断多个值
多个值以,隔开

  let sex = 0
  switch sex {
  case 0, 1:
      print("正常人")
  default:
      print("其他")
  }

简单使用补充:
如果希望出现之前的case穿透,则可以使用关键字fallthrough

  let sex = 0
  switch sex {
  case 0:
      fallthrough
  case 1:
      print("正常人")
  default:
      print("其他")
  }

Switch支持多种数据类型
浮点型的switch判断

    let f = 3.14
    switch f {
    case 3.14:
        print("π")
    default:
        print("not π")
    }

支持字符串类型

  let m = 5
  let n = 10
  var result = 0
  let opration = "+"

  switch opration {
      case "+":
          result = m + n
      case "-":
          result = m - n
      case "*":
          result = m * n
      case "/":
          result = m / n
  default:
      result = 0
  }
  print(result)

switch支持区间判断
什么是区间?
通常我们指的是数字区间:010,100200
swift中的区间常见有两种
半开半闭区间:0..<10 表示:0~9,不包括10
闭区间:0...10 表示:0~10

  let score = 88
  switch score {
  case 0..<60:
      print("不及格")
  case 60..<80:
      print("几个")
  case 80..<90:
      print("良好")
  case 90..<100:
      print("优秀")
  default:
      print("满分")
  }

函数

1.函数的定义:func 函数名(参数1名: 参数类型, 参数2名: 参数类型) -> 返回值类型

func add(num: Int, otherNum: Int) -> Int {
    return num + otherNum
}
print(add(num: 10, otherNum: 20))

2.参数个数变化的函数定义:在函数的最后一个参数中用...来添加多个参数

//可变参数,只能在函数的最后一个参数中用...来添加多个参数
func addAllNums(nums: Float...) -> Float {
    var result : Float = 0.0
    for item in nums {
        result += item;
    }

    return result
}
print(addAllNums(nums: 10, 20, 30, 40, 50, 60, 70, 80, 90, 100))

3.带默认参数的函数

//默认参数
func circleArea(r: Double = 10) -> Double{
    return M_PI*r*r
}
print(circleArea())
print(circleArea(r: 100))

4.高阶函数:Swift中函数可以做参数也可以做返回值

//找出最大数
func findMax(nums: Double...) -> Double {
    var result : Double = -Double.infinity//负无穷大
    for item in nums {
        if item > result {
            result = item
        }
    }

    return result
}
print(findMax(nums: 12, 3333, 32413, 324, 34124, 3432))
//找出最小数
func findMin(nums: Double...) -> Double {
    var result : Double = Double.infinity
    for item in nums {
        if item < result {
            result = item
        }
    }

    return result
}
print(findMin(nums: 12, 3333, 32413, 324, 34124, 3432))

//函数返回函数
func findNum(type: String) -> (Double...) -> (Double) {
    if type == "max" || type == "Max" {
        return findMax
    }
    return findMin
}
print(findNum(type: "Max")(1,2,3,4,32,32,4,34,23) + findNum(type: "Min")(2,32,323,233,1,323))

5.函数嵌套:在函数中定义使用函数

//函数嵌套
func randomNum(type:String) -> Int {
    func randomPositive() -> Int {
        return Int(arc4random())
    }
    func randomNegative() -> Int {
        return -(Int)(arc4random())
    }
    if type == "randomPositive" {
        return randomPositive()
    }
    return randomNegative()
}
print(randomNum(type: "randomPositive"))
print(randomNum(type: "randomNegative"))

注意:函数中的参数inout关键字会改变函数体外的变量值,同时在调用该函数的时候,此参数需传地址而不是值。

//变量参数,inout关键字会改变函数体外的变量值

func ascendingSort(num1: inout Int, num2: inout Int, num3: inout Int) -> [Int]
{
    var temp : Int
    if num1 > num2 {
        temp = num1;
        num1 = num2;
        num2 = temp;
    }
    if num2 > num3 {
        temp = num2;
        num2 = num3;
        num3 = temp;
    }
    return [num1, num2, num3]
}
var num1 = 3
var num2 = 2
var num3 = 4
print(ascendingSort(num1: &num1, num2: &num2, num3: &num3))
print([num1, num2, num3])

6.类的析构函数
析构函数
Swift 会自动释放不再需要的实例以释放资源
Swift 通过自动引用计数(ARC)处理实例的内存管理
当引用计数为0时,系统会自动调用析构函数(不可以手动调用)
通常在析构函数中释放一些资源(如移除通知等操作)
析构函数的写法

    deinit {
        // 执行析构过程
    }

闭包

闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。
Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 匿名函数比较相似。
全局函数和嵌套函数其实就是特殊的闭包。

  • 闭包的形式有:

    • 全局函数 嵌套函数 闭包表达式
    • 有名字但不能捕获任何值。 有名字,也能捕获封闭函数内的值。 无名闭包,使用轻量级语法,可以根据上下文环境捕获值。
  • Swift中的闭包有很多优化的地方:

    • 根据上下文推断参数和返回值类型
    • 从单行表达式闭包中隐式返回(也就是闭包体只有一行代码,可以省略return)
    • 可以使用简化参数名,如0,1(从0开始,表示第i个参数...)
    • 提供了尾随闭包语法(Trailing closure syntax)
  • 语法
    以下定义了一个接收参数并返回指定类型的闭包语法:

{(parameters) -> return type in
   statements
}

实例

let studname = { print("Swift 闭包实例。") }
studname()
以上程序执行输出结果为:
Swift 闭包实例。

1.说明:闭包与函数类似,就是一个代码块分装了其所处环境的所有状态。在闭包之前声明的所有变量常量都会被闭包所捕获,从本质上说闭包保留定义它时的程序状态。函数是有名称的闭包,闭包是无名称的函数。
2.定义一个计算单利的闭包

var simpleClosure = {(amount: Double, interestRate: inout Double, years: Int) -> Double in
    interestRate = interestRate/100
    var interest = Double(years) * interestRate * amount

    return interest + amount
}

3.高阶函数就是使用(闭包或函数)作为参数或返回值

//闭包做函数的参数
func loanCalculator(amount: Double, interestRate: inout Double, years: Int, calculator: (Double, inout Double, Int) -> Double) -> Double
{
    return calculator(amount, &interestRate, years)
}
var rate : Double = 3.875
print(loanCalculator(amount: 10000, interestRate: &rate, years: 5, calculator: simpleClosure))

4.sorted 方法
Swift 标准库提供了名为 sorted(by:) 的方法,会根据您提供的用于排序的闭包函数将已知类型数组中的值进行排序。
排序完成后,sorted(by:) 方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。原数组不会被 sorted(by:) 方法修改。

  • sorted(by:)方法需要传入两个参数:
    • 已知类型的数组
    • 闭包函数,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回 true,反之返回 false。
      实例
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"]

如果第一个字符串 (s1) 大于第二个字符串 (s2),backwards函数返回true,表示在新的数组中s1应该出现在s2前。 对于字符串中的字符来说,"大于" 表示 "按照字母顺序较晚出现"。 这意味着字母"B"大于字母"A",字符串"S"大于字符串"D"。 其将进行字母逆序排序,"AT"将会排在"AE"之前。

  • 参数名称缩写
    Swift 自动为内联函数提供了参数名称缩写功能,您可以直接通过0,1,$2来顺序调用闭包的参数。
    实例
let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted( by: { $0 > $1 } )
print(reversed)
$0和$1表示闭包中第一个和第二个String类型的参数。
以上程序执行输出结果为:
["S", "D", "BE", "AT", "AE"]

如果你在闭包表达式中使用参数名称缩写, 您可以在闭包参数列表中省略对其定义, 并且对应参数名称缩写的类型会通过函数类型进行推断。in 关键字同样也可以被省略.

  • 运算符函数
    实际上还有一种更简短的方式来撰写上面例子中的闭包表达式。
    Swift 的String类型定义了关于大于号 (>) 的字符串实现,其作为一个函数接受两个String类型的参数并返回Bool类型的值。 而这正好与sort(_:)方法的第二个参数需要的函数类型相符合。 因此,您可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现:
let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted(by: >)
print(reversed)
以上程序执行输出结果为:
["S", "D", "BE", "AT", "AE"]
  • 尾随闭包
    尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。
func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 函数体部分
}
// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
    // 闭包主体部分
})
// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
  // 闭包主体部分
}

实例

let names = ["AT", "AE", "D", "S", "BE"]
//尾随闭包
var reversed = names.sorted() { $0 > $1 }
print(reversed)
sort() 后的 { $0 > $1} 为尾随闭包。
以上程序执行输出结果为:
["S", "D", "BE", "AT", "AE"]

注意: 如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把()省略掉。
reversed = names.sorted { 0 >1 }

  • 捕获值
    闭包可以在其定义的上下文中捕获常量或变量。
    即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
    Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的函数体内的函数。
    嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。
    看这个例子:
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return increment or
}

一个函数makeIncrementor ,它有一个Int型的参数amout, 并且它有一个外部参数名字forIncremet,意味着你调用的时候,必须使用这个外部名字。返回值是一个()-> Int的函数。
函数题内,声明了变量runningTotal 和一个函数incrementor。
incrementor函数并没有获取任何参数,但是在函数体内访问了runningTotal和amount变量。这是因为其通过捕获在包含它的函数体内已经存在的runningTotal和amount变量而实现。
由于没有修改amount变量,incrementor实际上捕获并存储了该变量的一个副本,而该副本随着incrementor一同被存储。

  • 闭包是引用类型
    无论您将函数/闭包赋值给一个常量还是变量,您实际上都是将常量/变量的值设置为对应函数/闭包的引用。

枚举

枚举简单的说也是一种数据类型,只不过是这种数据类型只包含自定义的特定数据,它是一组有共同特性的数据的集合。
Swift 的枚举类似于 Objective C 和 C 的结构,

  • 枚举的功能为:
    它声明在类中,可以通过实例化类来访问它的值。
    枚举也可以定义构造函数(initializers)来提供一个初始成员值;可以在原始的实现基础上扩展它们的功能。
    可以遵守协议(protocols)来提供标准的功能。
  • 语法
    Swift 中使用 enum 关键词来创建枚举并且把它们的整个定义放在一对大括号内:
enum enumname {
   // 枚举定义放在这里
}
  • 相关值
    以下实例中我们定义一个名为 Student 的枚举类型,它可以是 Mark 的一个相关值(Int,Int,Int,Int),或者是 Name 的一个字符串类型(String)相关值。
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。
  • 原始值
    原始值可以是字符串,字符,或者任何整型值或浮点型值。每个原始值在它的枚举声明中必须是唯一的。
    在原始值为整数的枚举时,不需要显式的为每一个成员赋值,Swift会自动为你赋值。
    例如,当使用整数作为原始值时,隐式赋值的值依次递增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。

枚举的定义方式如下,可以给枚举类型的数据设置值也可以不设置值

/// 颜色类型枚举
enum ColorType {
    case RGB
    case CMYK
    case HSB
}
let type: ColorType = .RGB
print(type)

/// 学科枚举
enum Subject: String {
    case Chinese = "语文"
    case Math = "数学"
    case English = "英语"
}
let subjece: Subject = .Chinese
print(subjece)

注意: 和 C 和 Objective-C 不同,Swift 的枚举成员在被创建时不会被赋予一个默认的整型值。

结构体

Swift 结构体是构建代码所用的一种通用且灵活的构造体。
我们可以为结构体定义属性(常量、变量)和添加方法,从而扩展结构体的功能。

  • 与 C 和 Objective C 不同的是:
    结构体不需要包含实现文件和接口。
    结构体允许我们创建一个单一文件,且系统会自动生成面向其它代码的外部接口。
    结构体总是通过被复制的方式在代码中传递,因此它的值是不可修改的。
  • 语法
我们通过关键字 struct 来定义结构体:
struct nameStruct { 
   Definition 1
   Definition 2
   ……
   Definition N
}

实例
我们定义一个名为 MarkStruct 的结构体 ,结构体的属性为学生三个科目的分数,数据类型为 Int:

struct MarkStruct{
   var mark1: Int
   var mark2: Int
   var mark3: Int
}

我们可以通过结构体名来访问结构体成员。
结构体实例化使用 let 关键字:

struct studentMarks {
   var mark1 = 100
   var mark2 = 78
   var mark3 = 98
}
let marks = studentMarks()
print("Mark1 是 \(marks.mark1)")
print("Mark2 是 \(marks.mark2)")
print("Mark3 是 \(marks.mark3)")
以上程序执行输出结果为:
Mark1 是 100
Mark2 是 78
Mark3 是 98
  • 结构体应用
    在你的代码中,你可以使用结构体来定义你的自定义数据类型。
    结构体实例总是通过值传递来定义你的自定义数据类型。
    按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:
    • 结构体的主要目的是用来封装少量相关简单数据值。
    • 有理由预计一个结构体实例在赋值或传递时,封装的数据将会被拷贝而不是被引用。
    • 任何在结构体中储存的值类型属性,也将会被拷贝,而不是被引用。
    • 结构体不需要去继承另一个已存在类型的属性或者行为。

Swift中的结构体和C语言类似,同时Swift的结构体还包括方法,这使得与类十分相似。不过结构体是不能继承的,并且结构体是值类型的数据结构,而类是引用类型的数据结构。

  • 值类型:每次赋值都将创建副本,并把副本赋值给新的变量或常量,变量或常量存储的是副本。
  • 引用类型:说白了,引用类型就是指针,不管赋值给多少变量或者常量,他们都指向同一个对象,变量和常量存储的都是指向这个对象的引用,而不是副本。
struct Color {
  var R: Double = 0.0
  var G: Double = 0.0
  var B: Double = 0.0
  var Alpha: Double = 0.0

  func stringValue() -> String {
      let limit: Double = 255.0
      let rInt: Int = Int(self.R*limit)
      let gInt: Int = Int(self.G*limit)
      let bInt: Int = Int(self.B*limit)
      let alphaInt: Int = Int(self.Alpha*limit)

      let result: String = String.init(format: "%02X%02X%02X%02X", rInt, gInt, bInt, alphaInt)
      return result
  }
}
let red: Color = Color(R: 1.0, G: 0.0, B: 0.0, Alpha: 1)
print(red)
print(red.stringValue())

Swift 类是构建代码所用的一种通用且灵活的构造体。
我们可以为类定义属性(常量、变量)和方法。
与其他编程语言所不同的是,Swift 并不要求你为自定义类去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类,系统会自动生成面向其它代码的外部接口。

  • 类和结构体对比
    Swift 中类和结构体有很多共同点。共同处在于:
    定义属性用于存储值
    定义方法用于提供功能
    定义附属脚本用于访问值
    定义构造器用于生成初始化值
    通过扩展以增加默认实现的功能
    符合协议以对某类提供标准功能
    与结构体相比,类还有如下的附加功能:
    继承允许一个类继承另一个类的特征
    类型转换允许在运行时检查和解释一个类实例的类型
    解构器允许一个类实例释放任何其所被分配的资源
    引用计数允许对一个类的多次引用
  • 语法:
Class classname {
   Definition 1
   Definition 2
   ……
   Definition N
}

类定义

class student{
   var studname: String
   var mark: Int 
   var mark2: Int 
}

实例化类:

let studrecord = student()

实例

class MarksStruct {
    var mark: Int
    init(mark: Int) {
        self.mark = mark
    }
}
class studentMarks {
    var mark = 300
}
let marks = studentMarks()
print("成绩为 \(marks.mark)")
以上程序执行输出结果为:
成绩为 300
  • 作为引用类型访问类属性
    类的属性可以通过 . 来访问。格式为:实例化类名.属性名:
class studentMarks{
    var mark1 = 11
    var mark2 = 22
}
let marks = studentMarks()
print("mark1 is \(marks.mark1)")
  • 恒等运算符
    因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例。
    为了能够判定两个常量或者变量是否引用同一个类实例,Swift 内建了两个恒等运算符:
    • 恒等运算符 运算符为:===
      如果两个常量或者变量引用同一个类实例则返回 true
    • 不恒等运算符 运算符为: !==
      如果两个常量或者变量引用不同一个类实例则返回 true

属性

Swift 属性将值跟特定的类、结构或枚举关联。
属性也可以直接用于类型本身,这种属性称为类型属性。
另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己写的存储属性上,也可以添加到从父类继承的属性上。
属性可分为存储属性和计算属性:
1.存储属性 存储常量或变量作为实例的一部分 用于类和结构体
简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。
存储属性可以是变量存储属性(用关键字var定义),也可以是常量存储属性(用关键字let定义)。

  • 可以在定义存储属性的时候指定默认值
  • 也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值
  • 如果你定义的是一个常量存储属性,如果尝试修改它就会报错,如下所示:
struct Number
{
    var digits: Int
    let numbers = 3.1415
}
var n = Number(digits: 12345)
n.digits = 67
print("\(n.digits)")
print("\(n.numbers)")
n.numbers = 8.7
以上程序,执行会报错,错误如下所示:
error: cannot assign to property: 'numbers' is a 'let' constant
n.numbers = 8.7
  • 延迟存储属性
    延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。
    在属性声明前使用 lazy 来标示一个延迟存储属性。
    • 注意:
      必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
    • 延迟存储属性一般用于:
      延迟对象的创建。
      当属性的值依赖于其他未知类
      实例
class sample {
    lazy var no = number() // `var` 关键字是必须的
}
class number {
    var name = "Runoob Swift 教程"
}
var firstsample = sample()
print(firstsample.no.name)
以上程序执行输出结果为:
Runoob Swift 教程

2.计算属性 计算(而不是存储)一个值 用于类、结构体和枚举
计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。

  • 只读计算属性
    只有 getter 没有 setter 的计算属性就是只读计算属性。
    只读计算属性总是返回一个值,可以通过点(.)运算符访问,但不能设置新的值。
    注意:
    必须使用var关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。

3.属性观察器
属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时候也不例外。
可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。
注意:
不需要为无法重载的计算属性添加属性观察器,因为可以通过 setter 直接监控和响应值的变化。

  • 可以为属性添加如下的一个或全部观察器:
    willSet在设置新的值之前调用
    didSet在新的值被设置之后立即调用
    willSet和didSet观察器在属性初始化过程中不会被调用
    实例
class Samplepgm {
    var counter: Int = 0{
        willSet(newTotal){
            print("计数器: \(newTotal)")
        }
        didSet{
            if counter > oldValue {
                print("新增数 \(counter - oldValue)")
            }
        }
    }
}
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800
以上程序执行输出结果为:
计数器: 100
新增数 100
计数器: 800
新增数 700

4.实例化变量
如果您有过 Objective-C 经验,应该知道Objective-C 为类实例存储值和引用提供两种方法。对于属性来说,也可以使用实例变量作为属性值的后端存储。
Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。
一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。

5.全局变量和局部变量
计算属性和属性观察器所描述的模式也可以用于全局变量和局部变量。

  • 局部变量 在函数、方法或闭包内部定义的变量。 用于存储和检索值。 存储属性用于获取和设置值。也用于计算属性。

  • 全局变量 函数、方法、闭包或任何类型之外定义的变量。 用于存储和检索值。 存储属性用于获取和设置值。 也用于计算属性。

6.类型属性
类型属性是作为类型定义的一部分写在类型最外层的花括号({})内。
使用关键字 static 来定义值类型的类型属性,关键字 class 来为类定义类型属性。

struct Structname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // 这里返回一个 Int 值
   }
}

enum Enumname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // 这里返回一个 Int 值
   }
}

class Classname {
   class var computedTypeProperty: Int {
      // 这里返回一个 Int 值
   }
}

注意:例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。

  • 获取和设置类型属性的值
    类似于实例的属性,类型属性的访问也是通过点运算符(.)来进行。但是,类型属性是通过类型本身来获取和设置,而不是通过实例。

方法

Swift 方法是与某些特定类型相关联的函数
在 Objective-C 中,类是唯一能定义方法的类型。但在 Swift 中,你不仅能选择是否要定义一个类/结构体/枚举,还能灵活的在你创建的类型(类/结构体/枚举)上定义方法。

  • 实例方法
    在 Swift 语言中,实例方法是属于某个特定类、结构体或者枚举类型实例的方法。
    实例方法提供以下方法:
    可以访问和修改实例属性
    提供与实例目的相关的功能
    实例方法要写在它所属的类型的前后大括号({})之间。
    实例方法能够隐式访问它所属类型的所有的其他实例方法和属性。
    实例方法只能被它所属的类的某个特定实例调用。
    实例方法不能脱离于现存的实例而被调用。
    语法
func funcname(Parameters) -> returntype
{
    Statement1
    Statement2
    ……
    Statement N
    return parameters
}

实例

class Counter {
    var count = 0
    func increment() {
        count += 1
    }
    func incrementBy(amount: Int) {
        count += amount
    }
    func reset() {
        count = 0
    }
}
// 初始计数值是0
let counter = Counter()
// 计数值现在是1
counter.increment()
// 计数值现在是6
counter.incrementBy(amount: 5)
print(counter.count)
// 计数值现在是0
counter.reset()
print(counter.count)
以上程序执行输出结果为:
6
0

Counter类定义了三个实例方法:

  • increment 让计数器按 1 递增;

  • incrementBy(amount: Int) 让计数器按一个指定的整数值递增;

  • reset 将计数器重置为0。

  • 方法的局部参数名称和外部参数名称
    Swift 函数参数可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用
    Swift 中的方法和 Objective-C 中的方法极其相似。像在 Objective-C 中一样,Swift 中方法的名称通常用一个介词指向方法的第一个参数,比如:with,for,by等等。
    Swift 默认仅给方法的第一个参数名称一个局部参数名称;默认同时给第二个和后续的参数名称为全局参数名称。

  • 是否提供外部名称设置
    我们强制在第一个参数添加外部名称把这个局部名称当作外部名称使用(Swift 2.0前是使用 # 号)。
    相反,我们呢也可以使用下划线(_)设置第二个及后续的参数不提供一个外部名称。

class multiplication {
    var count: Int = 0
    func incrementBy(first no1: Int, no2: Int) {
        count = no1 * no2
        print(count)
    }
}
let counter = multiplication()
counter.incrementBy(first: 800, no2: 3)
counter.incrementBy(first: 100, no2: 5)
  • self 属性
    类型的每一个实例都有一个隐含属性叫做self,self 完全等同于该实例本身。
    你可以在一个实例的实例方法中使用这个隐含的self属性来引用当前实例。
  • 在实例方法中修改值类型
    Swift 语言中结构体和枚举是值类型。一般情况下,值类型的属性不能在它的实例方法中被修改。
    但是,如果你确实需要在某个具体的方法中修改结构体或者枚举的属性,你可以选择变异(mutating)这个方法,然后方法就可以从方法内部改变它的属性;并且它做的任何改变在方法结束时还会保留在原始结构中。
    方法还可以给它隐含的self属性赋值一个全新的实例,这个新实例在方法结束后将替换原来的实例。
  • 在可变方法中给 self 赋值
    可变方法能够赋给隐含属性 self 一个全新的实例。
struct area {
    var length = 1
    var breadth = 1
    func area() -> Int {
        return length * breadth
    }
    mutating func scaleBy(res: Int) {
        self.length *= res
        self.breadth *= res
        print(length)
        print(breadth)
    }
}
var val = area(length: 3, breadth: 5)
val.scaleBy(res: 13)
以上程序执行输出结果为:39    65
  • 类型方法
    实例方法是被类型的某个实例调用的方法,你也可以定义类型本身调用的方法,这种方法就叫做类型方法。
    声明结构体和枚举的类型方法,在方法的func关键字之前加上关键字static。类可能会用关键字class来允许子类重写父类的实现方法。
    类型方法和实例方法一样用点号(.)语法调用。
class Math
{
    class func abs(number: Int) -> Int
    {
        if number < 0
        {
            return (-number)
        }
        else
        {
            return number
        }
    }
}
struct absno
{
    static func abs(number: Int) -> Int
    {
        if number < 0
        {
            return (-number)
        }
        else
        {
            return number
        }
    }
}
let no = Math.abs(number: -35)
let num = absno.abs(number: -5)
print(no)
print(num)
以上程序执行输出结果为:
35
5
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容