1.1、OC->Swift:变量、运算符、流程控制

零、概述

  • 类型别名:关键字typealias
typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min

一、变量、常量、运算符

  • 打印:print函数,字符串插值

    var nickName:String = "tony"
    // 字符串插值:打印变量值
    print("name\(nickName)")
    
  • 变量和常量的声明
    变量声明:var name = "Hui",变量值可以被修改。
    常量声明:let name = "Hui",常量值只能被初始化一次,二次赋值报错。

    let name = "hui"
    name = "new hui" // 编译报错:常量类型无法被修改
    
  • 变量的可变性约束:通过var和let进行约束,let不能被修改,var可以被修改。
    例如,可变字符串、可变数组、可变字典等都是定义为var,不可变的定义为let。

  • 类型推断 与 类型注解
    Swift默认支持类型推导(即自动推测变量的类型),也支持类型注解(即明确声明变量的类型);

    // 类型推导:name自动推导为Sting类型
    var name = "Hui"
    
    // 类型注解:nickName明确为String类型
    var nickName:String = "tony"
    
  • 类型检查(因此,类型安全)
    变量的类型一旦确定,就无法更改;如果赋不同类型的值,编译器会报错。
    这是因为,明确类型后的变量的内存布局已经完成。

    var name = "Hui"
    name == 123 // 报错:类型不匹配
    

2、内置变量

数值型字面量:即数值的表示方法
  • 一个十进制数,没有前缀
  • 一个二进制数,前缀是 0b
  • 一个八进制数,前缀是 0o
  • 一个十六进制数,前缀是 0x
let decimalInteger = 17
let binaryInteger = 0b10001       // 二进制的17
let octalInteger = 0o21           // 八进制的17
let hexadecimalInteger = 0x11     // 十六进制的17
类型转换问题
  • 不同类型变量或常量能存储的数值范围是不同的,如果数值超出了常量或者变量可存储的范围,编译的时候会报错。
  • 不同数值类型的变量相加,编译器会报错。
let value1:UInt8 = 10
let value2:UInt16 = 10
// Binary operator '+' cannot be applied to operands of type 'UInt8' and 'UInt16'
let count = value1 + value2
元组(tuples) —— 新增
  • 定义:把多个值组合成一个复合值,元组内的值可以是任意类型。
let http404Error = (404, "Not Found")
  • 元组的内容解析:即访问元组的内部变量
// 1、元组的内容分解:可以将一个元组的内容分解(decompose)成单独的常量和变量,然后你就可以正常使用它们.
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")

// 2、可以把要忽略的部分用下划线(_)标记:
let (justTheStatusCode, _) = http404Error

// 3、通过下标来访问元组中的单个元素,下标从零开始:
print("The status code is \(http404Error.0)")
print("The status message is \(http404Error.1)")

// 4、可以在定义元组的时候给单个元素命名:
let http200Status = (statusCode: 200, description: "OK")
// 无需内容分解,直接使用
print("The status code is \(http200Status.statusCode)")
print("The status code is \(http200Status.description)")

可选类型 与 可选类型解析 —— 新增
  • 可选类型表示两种可能:或者有值,或者根本没有值。
  • 语法:类型后面跟问号,类型?
var nilValue: String? = "Tom"
  • nil:表示它没有值。
    注意:非可选类型的变量,初始化无法显示赋值为nil。
// 编译报错:'nil' cannot initialize specified type 'String'
var nilValue:String = nil
可选类型解析(即访问 可选类型 变量)
  • 强制解析
    在可选值后面加一个感叹号(!)来获取值,这个惊叹号表示"我知道这个可选有值,请使用它"。
var nilValue:String? = "name"
if nilValue != nil {
    // 强制获取 可选类型变量 nilValue 的值
    print(nilValue!)
}
  • 可选绑定解析
    用来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。
    可选绑定可以用在 if 和 while 语句中。如下
if let name = nilValue {
  // 有值则解析值到name变量
  print(name)
} else {
  // nil,没有值分支
}

隐式解析的可选类型

  • 定义:即变量在第一次赋值之后,就确定之后一直有值。
  • 语法:类型!,其无需 强制类型解析
let assumedString: String! = "An implicitly unwrapped optional string."
// 控制判断
if assumedString != nil {
    let implicitString: String = assumedString
    print(implicitString)
}
  • 隐式解析可选类型 同样支持 可选类型解析
if let definiteString = assumedString {
    print(definiteString)
}

3、常用的内置类型

  • 整数:Int、Unit、Int8、Int32等。
  • 浮点数:Double —— 表示64位浮点值,Float —— 表示32位浮点值
  • 布尔值:Bool(true、false)

字符串

  • 单行和多行字符串
let singleLineString = "These are the same."
let multilineString = """
These are the same.
"""
  • 基础操作
let nickName:String = "Hello World"
print(nickName.isEmpty)
print(nickName.count)
print(nickName.utf8)

print("say " + nickName)
print(nickName.appending("!"))

print(nickName.hasPrefix("He"))
print(nickName.hasSuffix("World"))

// 遍历字符串里的字符
for ch in nickName {
    print(ch)
}

// 字符串相等
let n1 = "123"
let n2 = "abc"
print(n1 == n2) // false
print(n1 != n2)  // true
  • 字符串的访问
let nickName:String = "Hello World"
print("start=\(nickName.startIndex), end=\(nickName.endIndex)")
print(nickName[nickName.startIndex])
print(nickName[nickName.index(after: nickName.startIndex)])
print(nickName[nickName.index(before: nickName.endIndex)])
print(nickName[nickName.index(nickName.startIndex, offsetBy: 3)])

for index in nickName.indices {
   print("\(nickName[index]) ", terminator: "")
}
  • 字符串的插入和删除
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome 变量现在等于 "hello!"

welcome.insert(contentsOf:" there", at: welcome.index(before: welcome.endIndex))
// welcome 变量现在等于 "hello there!"

welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome 现在等于 "hello there"


// 支持:区间运算符
let range = welcome.index(welcome.endIndex, offsetBy: -6) ..< welcome.endIndex
welcome.removeSubrange(range)
// welcome 现在等于 "hello"
  • 子字符串(其实质是一个 SubString 的实例)
// 1、prefix
print(greeting.prefix(2))

// 2、数组下标
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning 的值为 "Hello"
print(beginning)

// 3、把结果转化为 String 以便长期存储。
let newString = String(beginning)
print(newString)
  • 在 Swift 中, String 类型 是 值类型
    如果你创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。

  • 字符串插值:\(变量),即把变量的值插入到字符串中

let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"

集合类型(数组、集合、字典)

  • 数组、集合、字典它们之间的差别如下:


    image.png
  • 集合类型的可变性:var可变,let不可变(编译器会优化不可变集合类型,以达到内存最优)。

数组(Array)
  • 数组的创建
    func testArray() {
        // 1、声明具体类型数组
        var someInts = [Int]()
        print(someInts)

        // 编译报错:Cannot convert value of type 'Double' to expected argument type 'Int'
        //someInts.append(10.0)
        
        someInts.append(1)
        print(someInts.count)
        
        // 数组清空
        someInts = []
        print(someInts)
        
        // 2、构造函数创建:带有默认值的数组
        let doubles_1 = Array(repeating: 0.0, count: 3)
        let doubles_2 = Array(repeating: 10.0, count: 6)
        print(doubles_1 + doubles_2)
        
        // 3、字面量构造数组
        var shoppingList: [String] = ["123", "Eggs", "Milk"]
        
        shoppingList[0] = "Apples"
        print(shoppingList[0])
        print("区间运算符:\(shoppingList[1...2])")

        // 数组遍历
        for val in shoppingList {
            print(val)
        }
        for (index, value) in shoppingList.enumerated() {
            print("list[\(index+1)] = \(value)");
        }
        
        shoppingList.append("Pear")
        print(shoppingList.isEmpty)
        
        // 3、插入和删除
        shoppingList.insert("err", at: 0)
        shoppingList.remove(at: 0)
        print(shoppingList)

        shoppingList.insert("1", at: 0)
        shoppingList.append("2") // 末尾添加
        print("删除最后一个:\(shoppingList.removeLast())")
        print("删除第一个:\(shoppingList.removeFirst())")
        print(shoppingList)
    }
字典Dictionary<Key, Value>
func testDic() {
        // 1、创建:具体类型声明字典
        var namesOfIntegers = [Int: String]()
        namesOfIntegers[16] = "sixteen"
        print(namesOfIntegers)
        // 赋空字典
        namesOfIntegers = [:]
        print(namesOfIntegers)
        
        // 2、创建:字面量创建字典
        var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
        print(airports)
        
        let airports_1 = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
        print(airports_1)
        
        // 访问
        print(airports.count)
        print(airports.isEmpty)
        
        airports["LHR"] = "London"
        print(airports)
        
        // 删除
        airports["APL"] = "Apple Internation"
        airports["APL"] = nil
        print(airports)
        
        airports.removeValue(forKey: "LHR")
        print(airports)
        
        // 遍历
        for (key,value) in airports {
            print("key:\(key), value:\(value)")
        }
        print("allKeys:\(airports.keys)")
        print("allValues:\(airports.values)")
    }

二、运算符

以下只列出Swift特有的,其他大致同C语言类似。

  • 赋值运算符:Swift 的赋值操作并不返回任何值。
// 此句错误,因为 x = y 并不返回任何值。这样可以避免把 (==)错写成(=)这类错误的出现。
if x = y {
  ...
}
  • 区间运算符
    闭区间运算符:a...b,包括b,a不能超过b。
    半开区间运算符:a..<b,不包括b,a不能超过b。
for index in 0...5 {
    print(index)
}

let names = ["Anna", "Alex", "Brian", "Jack"]
for i in 0..< names.count {
    print(names[i])
}
  • 单侧区间运算符
    闭区间的单侧闭区间:如 names[2...]/names[...2]
    半开区间的单侧闭区间:如 names[..<2]
for name in names[2...] {
    print(name)
}
// Brian
// Jack

for name in names[...2] {
    print(name)
}
// Anna
// Alex
// Brian

for name in names[..<2] {
    print(name)
}
// Anna
// Alex
  • 恒等=== 和 不恒等!==运算符:用来判断 两个对象 是否引用同一个 对象实例。
let s1 = "123"
let s2 = "123"
// true
print(s1 == s2) 

这两个运算符无法用于 值类型 的变量或常量。

class Person {
    var name = ""
}
let p1 = Person()
let p2 = Person()
print(p1 === p2)

/*
2、 值类型
*/
struct Stack {
    var counts = 0
}
let st1 = Stack()
let st2 = Stack()
// error: argument type 'Stack' expected to be an instance of a class or class-constrained type
print(st1 === st2)

// error: argument type 'String' expected to be an instance of a class or class-constrained type
print(s1 === s2) 
  • 空合运算符:针对可选类型的判空判断
    a ?? b 将对可选类型 a 进行空判断,如果 a 包含一个值就进行解包,否则就返回一个默认值 b。
    注意:表达式 a 必须是 Optional 类型;默认值 b 的类型必须要和 a 存储值的类型保持一致。

    a ?? b 等价于 a != nil ? a! : b


三、控制流

1、其他与C语言大致一样,但Swift是不需要额外的括号,如下

while square < finalSquare {
    ...
}

if a < b {

} else if {}

temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
    print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
    print("It's really warm. Don't forget to wear sunscreen.")
} else {
    print("It's not that cold. Wear a t-shirt.")
}

2、新特性

  • 支持for-in循环(如上数组字典遍历)

  • 支持repeat-while(等同于do-while

repeat {
    statements
} while condition

3、Switch —— 功能得到极大的加强

  • 注意:不存在隐式的贯穿(如需要手动贯穿,如下fallthrough)。
    与 C 和 Objective-C 中的 switch 语句不同,在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止 switch 语句,而不会像C语言继续自动的执行下一个 case 分支。

  • case:复合型,即多个分支合并成一个分支,逗号分开

let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
    print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
     "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
    print("\(someCharacter) is a consonant")
default:
    print("\(someCharacter) is not a vowel or a consonant")
}
// 输出“e is a vowel”
  • case:区间匹配
switch count {
  case 0:
    ...  
  case 1..<5: 
    ...
}
case 和 元组 搭配使用
  • case:元组匹配(下划线_来匹配所有可能的值)
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    print("\(somePoint) is at the origin")
case (_, 0):
    print("\(somePoint) is on the x-axis")
case (0, _):
    print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
    print("\(somePoint) is inside the box")
default:
    print("\(somePoint) is outside of the box")
}
// 输出“(1, 1) is inside the box”
  • case:值绑定(Value Bindings) —— 类似于 元组的内容分解
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
    print("on the x-axis with an x value of \(x)")
case (0, let y):
    print("on the y-axis with a y value of \(y)")
case let (x, y):
    print("somewhere else at (\(x), \(y))")
}
// 输出“on the x-axis with an x value of 2”
  • case:支持where 条件判断
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
    print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
    print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
    print("(\(x), \(y)) is just some arbitrary point")
}

// 输出“(1, -1) is on the line x == -y”

4、控制转移语句

  • continue、break、return

  • fallthrough:
    用于switch中,从一个case跳到下一个case;这是因为Swift中的switch是执行完case不会在执行下一个case,所以实现C语言的Switch贯穿特性。

  • 带标签的语句:label xxxName: 代码块

label xxxName: while condition {
     statements
 }
  • guard语句,提前退出
    要求条件必须为真时,才继续执行 guard 语句后的代码,否则退出。
func greet(person: [String: String]) {
    guard let name = person["name"] else {
        return
    }

    print("Hello \(name)!")

    guard let location = person["location"] else {
        print("I hope the weather is nice near you.")
        return
    }

    print("I hope the weather is nice in \(location).")
}

greet(person: ["name": "John"])
// 输出“Hello John!”
// 输出“I hope the weather is nice near you.”
greet(person: ["name": "Jane", "location": "Cupertino"])
// 输出“Hello Jane!”
// 输出“I hope the weather is nice in Cupertino.”
  • #available(...) 检测API的可用性
if #available(iOS 10, macOS 10.12, *) {
    // 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API
} else {
    // 使用先前版本的 iOS 和 macOS 的 API
}

参考

菜鸟-Swift教程
官网-Swift手册

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容