swift 2.0

第一章 简介

2014年:swift 1 

2015年:swift 2 

可以把Swift看成是运用现代编程理念重写的,使用安全编程(safe programming)设计,源于Objective-C, Rust, Haskell, Ruby, Python, C#, CLU等重新设计的新语言。

Swift不再需要保持和C的兼容性,使得她可以拥有很多新的属性:


自动类型推断(Type Inference) Swift可以根据初始值自动推断出变量或常量的类型
范型 范型使得Swift可以为不同类型的类执行相同的代码
Collection Mutability “Swift does not have separate objects for mutable or non-mutable containers. Instead, you define mutability by defining the container as a constant or variable.”


摘录来自: “Mastering Swift 2”。 iBooks. 
代码块(Closure Syntax) 代码块是一份可以被传递与使用的自包含性代码
Optional Optional定义了一种变量,这种变量的值不是必须的,可能没有值
Switch Switch语法被显著地优化与提升了
多值返回 函数可以用tuples返回多个值
Operator重载 每个累都可以实现他们的Operator重载
关联性的枚举 可以定义比一般意义上复杂得多的枚举,不只是互相联系的值

Mix and Match属性:让我们可以在一个项目里面同时存在Swift和Objective-C文件。还可以让我们更新现有的Objective-C应用程序到Swift并且在Swift项目里使用原有的Objective-C库。

Playground

这里的实例代码都是在playground中运行,playground分为三个部分,左边代码,右边可以实时显示结果甚至图片,颜色等,下面是debug,debug面板是默认不现实的,可以shift + cmd + Y调出。正如其名,playground是用来尝试api和新东西的。

注释写法

/// 单行注释

/**
多行注释
*/

/**
    My add function, add them together and 
    return results.
    - parameters: 
        - first: The first integer
        - second: second The second integer
    - returns: The sum
*/
func myAdd(first: Int, second: Int) -> Int{
    let results = first + second
    return results
}



分号

分号不是必须的,强烈推荐不使用分号。

括号

判断条件里面的括号不是必须的,推荐不写最外层的括号

var x = 1
var y = 2
var z = 3

if x == 1 {
    print("ok")
}



花括号

花括号是必须的

判断条件里面的赋值

判断条件里的赋值是会编译出错的

if x = 1 { // 这样会报错

}



白色空格不是必须的

var n=0 // 没有白色空格
var m = 0 // 有白色空格



print函数

可以用逗号隔开,打印出多个值拼接在一起,也可以使用\( )来输出变量或常量值

var name = "jeff"
var language = "swift"

var message1 = " Welcome to the wonderful world of "
var message2 = "\(name) Welcome to the wonderful world of \(language)!"
print(name, message1, language)
print(message2)

print函数还可以带可选三个参数,separator表示使用什么分隔符,terminator表示使用什么结束符,toStream表示输出到哪个流


var name1 = "jeff"
var name2 = "john"
var name3 = "alice"

var line = ""

print(name1, name2, name3, separator:", ", terminator:" over", toStream: &line)

print(line)



常量和变量

在swift,常量是被鼓励的,在swift 2和xcode 7,如果定义了一个不变的变量会得到警告。因为定义常量可以减少错误率。常量用let定义。多个常量或者变量可以用逗号隔开。

类型安全


swift是类型安全的语言,如果我们赋值一种值到另外一种类型的变量中,会出现编译错误


var age = 25
age = "good" // 编译报错



类型推断

swift会根据初始值推断变量的类型


显式定义类型

我们还可以显式地定义变量类型

var x : Float = 3.14

如果我们不初始化变量值,必须显式地定义变量类型


var para  // 编译报错: error: type annotation missing in pattern
var a : Int  //正确



变量类型

Int


Type Minimum Maximum
Int8 -128 127
Int16 -32768 32767
Int32 -2147483648 2147283647
Int64 -9,223,372,036,854,775,808
9223372036854775807
Int -9,223,372,036,854,775,808
9223372036854775807
UInt8 0 255
UInt16 0 65535
UInt32 0 42945672945
UInt64 0 18446744073709551615
UInt 0 18446744073709551615
将下列进制前缀放在变量前可以定义不同进制的整形


进制 前缀
十进制 没有
二进制 0b
八进制 0o
十六进制 0x

swift还支持在数字里面加下划线增加可读性


var speedOfLight = 300_000



浮点数

如果没有特殊原因,推荐使用Double,不推荐使用Float,请看下面例子,同样是九位小数点的运算,Float的结果只有七位,而Double有九位。

let f : Float = 0.111_111_111 + 0.222_222_222  // 结果是0.3333333
let d : Double = 0.111_111_111 + 0.222_222_222 // 结果是0.333333333



类型转换

每个类型都有一个转换方法可以调用,Int必须要转换成Double才能和Double运算。


var a : Int = 3
var b : Double = 0.14
var c = Double(a) + b



布尔类型

没什么特别的

字符串类型

我们可以通过for循环来访问字符串里面的每一个字符

var strHello = "hello"
for char in strHello.characters {
    print(char)
}



如前面提到过,可以用\()来把一个字符串引用到另外一个字符串上
var myName = "jeff"
var helloString = "Hello \(myName)"



一些小技巧:


var stringOne = "hElLo"
print("capitalizedString:  " + stringOne.capitalizedString) // Hello
print("lowercaseString:  " + stringOne.lowercaseString) // hello
print("uppercaseString:  " + stringOne.uppercaseString) // HELLO



var stringOne = "Hello Swift"
var stringTwo = ""
stringOne.isEmpty  //false
stringTwo.isEmpty  //true
stringOne == "hello swift"  //false
stringOne == "Hello Swift"  //true
stringOne.hasPrefix("Hello")  //true
stringOne.hasSuffix("Hello")  //false”


Optional变量

可以用?来定义成Optional的变量或常量,Swift提供了三种方法来对Optional作安全检查

方法一:用!=nil判断

var stringOne: String?

if stringOne != nil {...}

方法二:if let / if var (Optional Binding)


var stringTwo: String?

if let tmp = stringTwo {...}



方法三: Optional Chaining


var stringOne: String?

var charCount = stringOne?.characters.count // return nil

枚举

通过enum和case关键字定义枚举,值得注意的是,当一个变量被推断成了枚举,后面就可以省略枚举类型直接引用枚举

enum Planets {
    case Earth, Mars
}
var live = Planets.Earth
live = .Mars // 省略写法,因为前面live已经被推断为Planets类型

上面例子没有用原始类型定义枚举,下面的例子是是用原始类型定义枚举


enum Devices:String {
    case iPod = "iPod"
    case iPhone = "iPhone"
}

之后就可以通过Devices.iPod.rawValue来访问枚举的值,还有一个神奇的特性就是,如果定义整形的枚举,并且定义了第一个枚举的值,后面的枚举的值如果不写,则会自动自增


enum NBAStars:Int {
    case Kobe = 8
    case Jeff
    case John
}
print("Kobe is number \(NBAStars.Kobe.rawValue)") // "Kobe is number 8\n"
print("Jeff is number \(NBAStars.Jeff.rawValue)") // "Jeff is number 9\n"
print("John is number \(NBAStars.John.rawValue)") // "John is number 10\n"



枚举还可以定义任意多关联值,每个枚举都可以定义不同的关联值


enum Product {
    case Book(Double, Int, Int)
    case Puzzle(Double, Int)
}

var masterSwift = Product.Book(29.9, 2015, 300)
var worldPuzzle = Product.Puzzle(9.9, 500)

switch masterSwift{
case .Book(let price, let year, let page):
    print("This book is published in year \(year) with \(page) pages and is sold for \(price) dollers")
case .Puzzle:
    print("This is not a book")
}

集合以及Cocoa数据类型

Array是一个有序的集合,Set是一个无序的非重复集合,Dictionary是无序的键值对集合。我们通常通过index访问Array,通过迭代访问Set,通过key访问Dictionary。Swift里面的集合只能使用同一种数据类型,不像以前的Objective-C可以使用不同类型。

Array


let arrayOne = [1,2,3]
var arrayTwo = [4,5,6]



如果定义空的Array必须要定义数据类型


var arrayThree = [Int]()


当然也可以通过Any或者AnyObject来定义不同类型的Array


var myArray: [AnyObject] = [1, "Two"]


我们还可以定义一个特定长度的Array并且都赋值同一个默认值


var arrayFout = [Int](count: 7, repeatedValue: 3)


定义二维Array
var multiArrayOne = [[1,2,3], [4,5,6]]
var multiArrayTwo = [[Int]]()

一些有用的属性与方法


  • first: 返回第一个元素
  • last: 返回最后一个元素
  • count: 返回数组长度
  • isEmpty: 是否为空
  • append(): 添加一个元素,使用+=也能达到同样的效果
  • insert(10, atIndex: 3): 把10插入到3的位置
  • 两个array可以通过+直接相连
  • reverse(): 反序
  • 提取从2到4的子数组:var subArray = arrayOne[2...4]
  • 直接修改子数组: arrayOne[2...4] = [12, 13, 14],后面的数组长度与前面的不一定一样长

Array算法

Array还可以用排序算法来对值进行排序


var arrayFive = [9, 5, 4, 8, 2, 7]
arrayFive.sortInPlace(){$0 < $1}

居然还有过滤器


var arrayFilter = [1, 2, 3, 4, 5, 6, 7, 8, 9]
let applied = arrayFilter.filter{$0 > 3 && $0 < 7}



var city = ["Boston", "London", "Chicago", "Atlanta"]
let filtered = city.filter{$0.rangeOfString("o") != nil}
//filtered contains "Boston", "London" and "Chicago”



有一个map方法,可以对数组里面的每一个元素进行操作并返回一个新的数组
var arrayMap = [10, 20, 30, 40]
let appliedMap = arrayMap.map{ $0 / 10}
//applied contains 1,2,3 and 4



还可以将全部的数组元素换一种类型


var arrayOneMap2 = [1, 2, 3, 4]
let appliedMap2 = arrayOne.map{ "num:\($0)"}
//applied contains "num:1", "num:2", "num:3" and "num:4



数组的遍历
第一种方法是用forEach(){}



var arrayOne = [10, 20, 30, 40]
arrayOne.forEach{ print($0) }



第二种方法是for-in


var arr = ["one", "two", "three"]
for item in arr {
    print(item)
}



有时候我们即需要数组的值又需要数组的index,这时候我们可以用enumerate方法得到一个tuple(后面将会讲到)


var arr = ["one", "two", "three"]
for (index,value) in arr.arr.enumerate() {
    print"\(index) \(value)")
}
上面例子用到了Clousure属性,后文将会另作解释,如果不想在原有的数组上排序,可以使用sort()

Dictionary

字典类型是用来存储键值对的集合

var myDictionary = ["US": "American", "year": 2016]
myDictionary["year"]
var dic1 = [String:String]()
var dic2 = [String:Int]()



从上面例子可以看到,其实还可以定义成不同值类型的字典,比较自由

下面列举一些常用的属性和方法


  • count
  • isEmpty
  • updateValue("Britain", forKey: "UK"): 将"UK"的值设为Britain,但是这个函数的返回值是修改之前的值,另外如果forKey里面的值不在字典里面,这个操作相当于增加一个键值对,并且返回nil
  • countries["IN"] = nil: 删除了一个键值对
  • removeValueForKey("UK"): 删除“UK”并且返回删除前的值
  • removeAll(): 删除所有

SET

集合是一种无序的不重复的数据类型


  • insert(): 插入一个值,如果该值已经存在,则插入操作将被忽略
  • contains()
  • 可以用for-in语句遍历
  • remove()
  • removeAll()
  • union()
  • unionInPlace()
  • subtract(): 减去
  • subtractInPlace()
  • intersect(): 重叠
  • intersectInPlace()
  • exclusiveOr(): 在其中一个集合,但是不是重叠的

Tuple

Tuple是一种把不同类型的数据放在一个集合里面的数据结构

var team = ("Boston", "Red Sox", 97, 65, 59.9)



下面的例子把一个tuple的值赋给了一个tuple的变量

var team = ("Boston", "Red Sox", 97, 65, 59.99)
var (city, name, wins, losses, percent) = team



还可以通过index得到tuple中某个值

var team = ("Boston", "Red Sox", 97, 65, 59.9)
var city = team.0
var name = team.1
var wins = team.2
var loses = team.3
var percent = team.4



我们还可以定义有键值的tuple

var team = (city:"Boston", name:"Red Sox", wins:97, loses:65, percent:59.9)



然后我们就可以通过team.city来调用里面的值,这种写法和javascript有异曲同工之妙

Cocoa类型

Swift还兼容Cocoa类型,有些Swift类型可以在内部转换成Cocoa类型,有些需要在外部显式地转换,这两种我们统称为bridge类型。

Swift还提供了对Foundation的封装,如果要引用Foundation数据类型,必须引用import Foundation

NSNumber

Swift编译器会自动把Int类型转换成NSNumber,但是从NSNumber转回Int需要显式地转换

var inum = 7    //Creates an Int
var dnum = 10.6 //Creates a Double
var insnum: NSNumber = inum  //Bridges the Int to a NSNumber
var dnsnum: NSNumber = dnum  //Bridges the Double to a NSNumber
var newint = Int(insnum)       //Creates an Int from a NSNumber
var newdouble = Double(dnsnum) //Creates a Double from a NSNumber

NSString

Swift本地的String类型可以自动转换为NSString类型,但是反过来不行,只能用as关键字来转化


var nsstr: NSString = "abc"
testFunc(nsstr as String)


入门

Classes

类需要注意一下几点:


  • 选择正确的名字
  • 继承
  • 实现protocol
  • 定义private和public


class ClassName: Superclass, Someprotocol{
    
}



class Temperature {
    var celsiusValue = 0.0
    
    // 构造方法
    init() {
    }
    
    // 类方法(静态方法)
    class func randomTemperature()-> Double {
        return 23.0
    }
}



新建一个实例


let aTemperatureInstance = Temperature()




Method

在swift里面,函数也叫方法,有以下几点需要注意


  • 方法即可以定义在类里面也可以定义在类外面
  • 方法可以有多个返回值(后面讲到)
  • 实例方法用func关键字定义
  • 类方法(即java里面的静态方法)用class func关键字定义

下面是完整的定义一个方法的语法


class func convertTempFromFahrenheit(fahrenheit: Double) -> Double {...}



extension

extension可以让你扩展你的类,使得一个类可以分配到多个文件,所有extension里面的东西都是共享的


extension Temperature {
    ...
}

Java和Swift的access control对比


Swift Java
public: 公开 public: 公开

protected: 类继承内可访问
internal: 同一个模块内可访问(默认) package: 同一个包内可访问(默认)
private: 同一个文件 private: 同一个类

以下写法会报错:


private class SomePrivateClass { 
}

func someFunction() -> SomePrivateClass {
    let myClass = SomePrivateClass()
    return myClass
}



因为定义了私有类,却通过默认的internal方法暴露出去了,正确的写法是:


private class SomePrivateClass { 
}

private func someFunc() -> SomePrivateClass {
    let myClass = SomePrivateClass()
    return myClass
}



类属性

Swift里面有两种类属性,一种是stored properties,他们的getter 和setter是在编译器默认创建的


class Temperature {
    var celsiusValue: Double
}



第二种类属性叫做computed properties,他的getter和setter是自己定义的


class Temperature {
    var description: String {
        get {
            return "3 degree"
        }
        set {
        }
    }
}

// 我们可以省略 setter
class Temperature {
    var description: String {
        get {
            return "3 degree"
        }
    }
}

// 甚至有种更简洁的写法
class Temperature {
    var description: String {
        return "3 degree"
    }
}



我们甚至可以定义带有access control的getter和setter


private(set) var celsiusValue: Int = 0.0 // 只能在类被定义的文件中set


控制

for循环

范围操作

  • n...m: 从n开始数到m,包括m
  • n..<m: 不包括m

var party = ["jef", "allen", "paipaibear"]
for i in 0..<party.count {
    print("party members: \(party[i])")
}



虽然上面的做法是正确的,但是推荐的做法如下:

for member in party {
    print("safer method to read array: \(member)")
}



下面是一个小小的联系代码

class Cup {
    var content: String
    var temperature: String
    
    var description: String {
        return "Your cup of \(content) is \(temperature) C hot"
    }
    
    init(content: String, temperature: String) {
        self.content = content
        self.temperature = temperature
    }
}

class TeaMaker {
    func boilCupOfTea(content: String) -> Cup {
        return Cup(content: content, temperature: "40 C")
    }
}

var teaOrders = [
    "Stephoan": "Earl Grey",
    "Lukas": "Green Tea",
    "Jan": "Black Tea",
    "Barbara": "Early Grey",
    "Margin": "Green Tea"
]

var myTeaMaker = TeaMaker()

for (guest, order) in teaOrders {
    var cupOfTea = myTeaMaker.boilCupOfTea(order)
    
    print("Hello \(guest). Beware! \(cupOfTea.description)")
}



最普通的for循环和java一样

for var index = 0; index < 10; index++ {
    print(index)
}



Tuples

// 创建tuple
var http404 = (404, "Not Found")

// 解压tuple
let (statusCode, statusMessage) = http404
print("The status code is \(statusCode)")
print("The status message is \(statusMessage)")



// 还可以为tuple的值起个名字
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
print("The status message is \(http200Status.description)")



Tuple有如下使用场景:

  • 枚举字典里的元素
  • 定义多个返回值的函数

但是不要用tuple来定义复杂的数据结构,要用class或sctruct




今天就写到这

未完待续...

转载于:https://my.oschina.net/LinJeffrey/blog/538904

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值