Swift 语言概览
参考资料
swift开源项目:
Questions
- Xcode 6不能查看类的定义??? *
swift教程
1. 常量和变量
常量使用let关键字进行声明
ps:
常量和变量的命名可以使用你喜欢的字符作为常量和变量名,包括Unicode 字符,比如 var �� = “suprise”。常量与变量名不能包含数学符号,箭头,保留的(或者非法的)Unicode 码位,连线与制
表符。也不能以数字开头,但是可以在常量与变量名的其他地方包含数字。
//1.常量定义
let myConst = 42
let explicitDouble : Double = 70 //类型信息不足时,使用:显示指定类型
//变量定义
var myVar = 50
//在符串中包含变量,使用"\(变量名)"进行转移
let apple = 3
let oranges = 5
let appleSummary = "I have \(apple) apples"
//数组和字典
int shoppingList = ["fish","meat","water"]
shoppingList[1] = "bottle of juice"
var employee = ["manager":"Jim","CEO":"Tim cook",]
let emptyArray = String[]()
注意:Swift 的 nil 和 Objective-C 中的 nil 并不一样。在 Objective-C 中,nil 是一个指向 不存在对象的指针。在 Swift 中,nil 不是指针——它是一个确定的值,用来表示值缺失。
任何类型的可选都可以被设置为 nil,不只是对象类型。
类型安全和类型推测
Swift 是一个类型安全(typesafe)的语言。类型安全的语言可以让你清楚地知道代码要处 理的值的类型。如果你的代码需要一个 String,你绝对不可能不小心传进去一个 Int。
当推测(inference)浮点数的类型时,Swift 总是会选择 Double 而不是 Float。
整数字面量可以被写作:
- 一个十进制数,没有前缀
- 一个二进制数,前缀是 0b
- 一个八进制数,前缀是 0o
- 一个十六进制数,前缀是 0x
隐式解析可选(?和!)
Character和String
注意:Swift 的 String 类型与 Foundation NSString 类进行了无缝桥接。如果您利用 Cocoa 或 Cocoa Touch 中的 Foundation 框架进行工作,整个 NSString API 都可以调用 您创建的任意 String 类型的值,除了本章介绍的 String 特性。您也可以在任意要求传入 NSString 实例作为参数的 API 中使用 String 类型的值进行替换。
Swift 的 String 类型是值类型。如果您创建了一个新的字符串值,那么当其进行常量、变量 赋值操作或在函数/方法中传递时,会进行值拷贝。
注意:
1.不同的 Unicode 字符以及相同 Unicode 字符的不同表示方式可能需要不同数量的 内存空间来存储,所以 Swift 中的字符在一个字符串中表示并不一定占用相同的内存空 间。因此,字符串的长度不得不通过迭代字符串中每一个字符的长度来进行计算。如果 您正在处理一个长字符串,需要注意 countElements 函数必须遍历字符串中的字符,以 精准计算字符串的长度。
2.另外需要注意的是通过 countElements 返回的字符数量并不总是与包含相同字符的 NSString 的 length 属性相同。NSString 的 length 属性是基于利用 UTF-16 表示的十六位 code units 数目,而不是基于 Unicode 字符。为了解决这个问题,NSString 的 length 属性在被 Swift 的 String 值访问时会被称为 utf16count。
2. 流程控制
swift中的流程控制语言包括if和switch条件语句;
for-in,for,while,do-while循环语句。条件或者循环变量之间的括号 ()是可选的,但是条件或者循环之间的内容之间的花括号{}是必须的
if条件语句:
let individualscores = [75,43,103,87,12]
var teamscore = 0
for score in individualscores
{
if score > 50{
teamscore += 3
}
else {
teamscore += 1
}
}
teamscore
switch条件语句
let vegatable = "red pepper"
switch vegatable
{
case "celery":
let vegatableComment = "add some raisins and make ants on log"
case let x where
x.haseSuffix("pepper") :
let vegatableComment = "Is it a spicy \(x)?"
default :
let vegatableComment = "everything tastes good in soup."
}
for in 语句
let interestingNums = [
"Prime" : [2,3,5,7],"Fibinacci" : [1,1,2,8],"Square" : [1,4,9,16,25],]
var largest = 0
for (kind,numbers) in interestingNums
{
for number in numbers
{
if number > largest
{
largest = number;
}
}
}
largest
var array[10] : String =
for (index,value) in enumerate(array) {
if value == valueToFind {
return index
}
}
while,do-while循环
//while循环
var n = 2
while n < 100
{
n = n * 2
}
n
//do - while循环
var m = 2
do {
m *= 2
} while m < 100
m
for 循环
var firstForLoop = 0
for i in 0..3
{ firstForLoop += i }
firstForLoop
var secondForLoop = 0
for var i = 0; i < 3; ++i
{ secondForLoop += 1 }
secondForLoop
where语句
case 块的模式可以使用 where 语句来判断额外的条件。
let yetAnotherPoint = (1,-1)
switch yetAnotherPoint {
case let (x,y) where x == y:
println("(\(x),\(y)) is on the line x == y")
case let (x,y) where x == -y:
println("(\(x),\(y)) is on the line x == -y")
case let (x,y):
println("(\(x),\(y)) is just some arbitrary point")
}
Fallthrough
Labeled Statements
值绑定(Value Bindings)
case 块的模式允许将匹配的值绑定到一个临时的常量或变量,这些常量或变量在该 case 块 里就可以被引用了——这种行为被称为值绑定。
控制转移语句
- continue
- break
- fallthrough
- return
fallthrough 关键字不会检查它下一个将会落入执行的 case 中的匹配条件。
fallthrough 简单地使代码执行继续连接到下一个 case 中的执行代码,这和 C 语言标准中的 switch 语句特性是一样的。
labeled statements(标签声明)
下面是一个demo,使用break语句配合switch语句退出最外层while循环功能
func test_labeledStatements()
{
let finalSquare = 25
var board = [Int](count: finalSquare + 1,repeatedValue: 0)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
var square = 0
var diceRoll = 0
gameLoop: while square != finalSquare {
if ++diceRoll == 7 { diceRoll = 1 }
switch square + diceRoll {
case finalSquare:
// diceRoll will move us to the final square,so the game is over
break gameLoop
case let newSquare where newSquare > finalSquare:
// diceRoll will move us beyond the final square,so roll again
continue gameLoop
default:
// this is a valid move,so find out its effect
square += diceRoll
square += board[square]
}
}
println("Game over!")
}
3. 函数
func greet(name:String,day:String) -> String
{
return "Hello \(name),today is \(day)."
}
greet("Bob","Wednesday")
多返回值的函数– 返回值是元组
func getGasPrices() -> (Double,Double,Double)
{
return (3.59,3.69,3.79)
}
getGasPrice()
多入参函数
func sumOf (nums: Int ...) -> Int
{
var sum = 0
for num in nums
{
sum += num
}
return sum
}
sumOf()
sumOf (42,34)
返回函数的函数
func makeIncrementer() -> (Int -> Int)
{
func addOne (number : Int) -> Int
{
return 1 + number
}
return addOne;
}
var increment = makeIncrementer () //获取函数变量
increment (7)
函数作为入参
func hasAnyMatches (list : Int[],condition : Int -> Bool) -> Bool
{
for item in list
{
if condition(item)
{
return true
}
}
return false
}
func lessThanTen (num: Int) -> Bool
{
return num < 10
}
var nums = [20,19,7,12]
hasAnyMatches (nums,lessThanTen)
常量形参和变量形参
函数的形参默认是常量。试图在函数体内改变函数形参的值会引发一个编译时错误。这意
味着你不能错误地改变形参的值。
但是有时候,函数有一个形参值的变量副本是非常有用的。您可以指定一个或多个形参作 为变量形参,从而避免在函数内部为自己定义一个新的变量。变量参数是变量而非常量,并 给函数一个可修改的形参值副本。
in-out 参数
在调用方法的时候,在方法中加上引用操作符 &,这样就可以调用方法,改变变量的值。
eg:
func swapTwoInts(inout a: Int,inout b: Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt,&anotherInt)
println("someInt is now \(someInt),and anotherInt is now \(anotherInt)") //someInt is now 107,and anotherInt is now 3
函数类型
下面两个函数的类型是:** (Int,Int) -> Int**
func addTwoInts(a: Int,b: Int) -> Int {
return a + b
}
func multiplyTwoInts(a: Int,b: Int) -> Int {
return a * b
}
无参数和返回值的函数类型: **() -> ()**
eg:
func printHelloWorld() {
println("hello,world")
}
嵌套函数(nested functions)
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int
{ return input + 1 }
func stepBackward(input: Int) -> Int
{ return input - 1 }
return backwards ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
println("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
println("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!
4. 闭包
闭包是功能性自包含模块,可以在代码中被传递和使用。 Swift 中的闭包与 C 和 Objective-C 中的 blocks 以及其他一些编程语言中的 lambdas 比较相似。
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。 这就是所谓的闭合并包裹着 这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的内存操作。
闭包语法
{ (parameters) -> return type in
statements
}
demo:
var closureReversed = sort(names,{ (s1: String,s2: String) -> Bool in
return s1 > s2
})
for value in closureReversed
{
println(value)
}
//tailing closure(尾随闭包)
var tailReversed = sort(names){$0 > $1} //闭包类型推断,无需指定参数类型和返回值类型,swift是有多动态~~
for value in reversed
{
println(value)
}
闭包是引用类型
变化方法(mutating关键字)
改变该对象的属性
mutating func test()
{ }
5.枚举类型(Enumerations)
和c语言枚举不同的是,swift枚举更富有弹性(flexible),值类型可以是string类型,字符类型和任意的整型或者浮点类型
//swift枚举和c,oc枚举的不同之处在于,swift枚举成员不会赋予一个默认整型值,比如说下面的枚举类型中North,South,East,West的值不是0,1,2,3
enum CompassPoint {
case North
case South
case East
case West
}
enum Planet {
case Mercury,Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune
}
关联值(Associated values)
6.类和结构体
swift中类和结构体的共同点:
- 定义属性(property),用于保存值
- 定义方法,用于提供功能
- 定义下标,用于访问它们的属性
- 定义初始化者,用于初始化它们的状态
- 在默认实现之外,提供方法扩展功能
- 响应协议(protocols),为指定类型提供标准方法
类相对于结构体的不同点
事实上,swift中所有的基础数据类型-整型,浮点型,布尔型,string,数组和字典,都是值类型,背后都是通过结构体类型实现的。所有的结构体类型,枚举类型都是值类型
//字典类型是值类型
var ages = ["Peter": 23,"Wei": 35,"Anish": 65,"Katya": 19]
var copiedAges = ages
copiedAges["Peter"] = 24
println(ages["Peter"]) //value is 23
identity Operations(标识操作符)
===,!==
=== 和 equel to (2个等号的 ==)是不同的,===指的是两个常量或者变量指向同一个对象实例。
7.属性(Property)
//结构体和类类型常量、变量的区别
func testProperty()
{
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
//结构体变量
var fixedLenVar = FixedLengthRange(firstValue:1,length:5)
fixedLenVar.firstValue = 10
//结构体常量
let fixedLenConst = FixedLengthRange(firstValue:1,length:5)
fixedLenConst.firstValue = 10 //编译报错
//类变量
var swiftVar : FirstSwiftClass = FirstSwiftClass()
swiftVar.index = 1
//类常量
let swiftConst : FirstSwiftClass = FirstSwiftClass()
swiftVar.index = 1
}
可选属性类型 ?
eg:
var response: String?
8.方法
//不需要参数标签,则在参数中加 -
// func incrementBy(amount: Int,_ numberOfTimes: Int) {
func incrementBy(amount: Int,_ numberOfTimes: Int) {
下标定义(subscript)
可以像数组,字典一样,使用下标访问类,结构体中的元素
struct Matrix {
let rows: Int,columns: Int
var grid: [Double]
init(rows: Int,columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(count: rows * columns,repeatedValue: 0.0)
}
func indexIsValidForRow(row: Int,column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int,column: Int) -> Double {
get {
assert(indexIsValidForRow(row,column: column),"Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValidForRow(row,"Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
继承 (inheritance)
禁止重写,使用@final
关键字
不像 Objective-C,在 Swift 中,初始化器默认是不继承的,见初始化器的继承与重写
析构函数(deinitialization)
deinit函数
9. ARC
weak引用
注意:弱引用只能声明为变量类型,因为运行时它的值可能改变。弱引用绝对不能声明为常量。
非持有引用(unowned reference)
和weak类似,非持有引用也不会保持强引用,但是非持有引用必须保证属性一定含有值。正因为如此,非持有引用总是定义为非可选值
闭包的循环引用问题
解决方法:
- 使用[unowned self] in
@lazy var asHTML: () -> String = {
[unowned self] in
...
}
10. 扩展 (Extensions)
Swift 中的扩展可以:
11. 范型(generics)
swift标准库定义了Equatable协议,该协议要求任何遵循的类型实现都完成”==”和”!=”的实现,用于比较2个该类型是否equal。
12.高级操作符(advanced operators)
不像C语言中的算数操作符,swift算数操作符默认不会溢出(overflow),溢出行为会被捕获,并报告为错误。
位操作符(bitwise operators)
|,&,~,^
<<,>>
溢出操作符(overflow operations)
- &+,溢出加
- &-,溢出减
&*,溢出乘
- &/,溢出除
- &%,溢出模
操作方法(operator functions)
操作方法类似于c++中的操作符重载
13. 其它
==== 类型推断(type casting)
Any 和 AnyObject 的转换
Swift 为不确定类型��供了两种特殊类型别名:
- AnyObject 可以代表任何 class 类型的实例。
- Any 可以表示任何类型,除了方法类型(function types)。 注意:只有当你明确的需要它的行为和功能时才使用 Any 和 AnyObject。在你的代码里使
用你期望的明确的类型总是更好的。
关于注释
和Objective-C中的#pragma mark
类似,swift中也可以使用// MARK: -
进行注释。