Swift入坑0x01基础

高屋建瓴

这节的基础内容主要参考官档Swift-The Basics,主要涵盖Swift中的常量,注释,各种变量,错误处理以及断言等的说明。

涉及到的概念比较多,这里先总结下作为Swift本章主要讲到的知识点。加粗的元组和optionals类型是Swift和OC相比特有的两个类型。

  • 常量和变量
  • 注释
  • 分号
  • 整数
  • 浮点数
  • 类型安全和判断
  • 数值型字面量
  • 数值类型转换
  • 类型别名
  • 布尔值
  • 元组
  • optionals类型
  • 错误处理
  • 断言

各个击破

常量和变量

官档原文

1.使用let定义常量/使用var定义变量
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0

2.多个常量或变量定义用逗号隔开

let maximumNumberOfLoginAttempts = 10, minNumberOfLoginAttempts = 1
var x = 0.0, y = 0.0, z = 0.0

3.变量类型标注

//声明关键字 + 变量名 + ":" + 变量类型
var welcomeMessage: String

//正确使用
welcomeMessage = "hello world"
//报错
welcomeMessage = 3

但是呢,你会发现在现实开发中我们往往很少给变量加类型说明,因为往往我们在定义的时候习惯给它初始化。

It’s rare that you need to write type annotations in practice. If you provide an initial value for a constant or variable at the point that it’s defined, Swift can almost always infer the type to be used for that constant or variable, as described in Type Safety and Type Inference. In the welcomeMessage example above, no initial value is provided, and so the type of the welcomeMessage variable is specified with a type annotation rather than being inferred from an initial value.

你很少需要在实践中使用类型标注。如果我们再定义常量/变量的时候提供初始化,Swift总是可以推断出用于该常量/变量的类型。但是正如 Type Safety and Type Inference所描述的,变量"welcomeMessage"并没有在定义的时候初始化,所以这个时候变量"welcomeMessage"的类型Swift就不能根据初始化的值推断,而是依赖于变量的类型标注(: String).

4.变量命名原则

  • a. 不能包含空格,数学符号,箭头符,专用的unicode值
  • b. 不能以数字开头
  • c. 驼峰

这点,基本所有语言都有共性。

5.变量打印

// Prints "The current value of friendlyWelcome is Bonjour!"
print("The current value of friendlyWelcome is \(friendlyWelcome)")

可以看出,这种打印方式还是很特别的。我们之前OC是使用NSLog做打印,虽然名称上与C有错不同。但是,打印方式上还是一脉相承,都需要在字符串打印格式中中使用占位符,然后再在格式之后按顺序跟着要打印的变量名。

//C
printf("hello these are %s and %s", "wen", "chaors");
//OC
NSLog(@"hello these are %@ and %@", @"wen", @"chaors");
//Swift
print("hello these are \("wen") and \("chaors")")

显然,Swift在打印格式中直接使用转义符(\)并将变量包装在小括号()内,使得打印看上去更加简洁。不过,刚从C/OC过来的我开始阶段还是稍有不适。

注释

官档原文

1.和大多数语言雷同的注释方式

//单行注释

/*
多行注释
第1行
第2行
...
*/

2.嵌套块注释

/* This is the start of the first multiline comment.
 /* This is the second, nested multiline comment. */
This is the end of the first multiline comment. */

这其实没什么可说的,不过增加这个支持后,对含有块注释的代码进行注释就方便多了。也许这样说还是不太明朗,我们拿OC举个例子。

OC不支持嵌套块注释

嵌套注释就是针对这种情况的解决方案,其实有时候还是蛮有用的。

分号

官档原文

想必我们也已经发现,前面写的Swift示例代码语句结尾都没有分号。

Unlike many other languages, Swift doesn’t require you to write a semicolon (;) after each statement in your code, although you can do so if you wish. However, semicolons are required if you want to write multiple separate statements on a single line.

不像其他语言,Swift并不要求在代码的每个语句之后添加分号(;).当然如果你愿意,你也可以这样做。但是,当一行有多个语句时就必须使用分号了。

C语言的编译器规定,每句代码必须使用";"作为分隔符,以便使编译器知道该语句执行到哪里结束。OC作为C的衍生语言,当然也将这一特点继承过来。但是,事实上,并不是所有的语言需要这样做。除了今天的Swift,单行一句代码不需要加分号的还有Js,Python等。

其实,在这个问题上有一个ASI(Automatic semicolon insertion)规则。简言之,就是分号自动插入。很多时候,并不是不需要分号,而是这件事编译器给我们做了。关于ASI具体的分析可以看这篇文章

整数

官档原文

1.和OC的概念基本相同,提供API访问范围

let minValue = UInt8.min  // minValue is equal to 0, and is of type UInt8
let maxValue = UInt8.max  // maxValue is equal to 255, and is of type UInt8

2.int/uint

On a 32-bit platform, Int(Uint) is the same size as Int32(Uint32).
On a 64-bit platform, Int (Uint) is the same size as Int64(Uint64).

浮点数

官档原文

Double represents a 64-bit floating-point number. 15位精度
Float represents a 32-bit floating-point number. 6位精度

类型安全和判断

官档原文

就是前面讲变量初始化和赋值时涉及到的,编译器会根据你给变量传递的数值类型来推断变量具体的类型。

这里,需要注意一个细节:

  • 1.对整数推断默认是int
  • 2.对浮点数推断默认是double

数值型字面量

官档原文

1.整数型字面量:

  • 十进制: 正常模式(无前缀)
  • 二进制: + 0b 前缀
  • 八进制: + 0o 前缀
  • 十六进制:+ 0x 前缀

eg:

let decimalInteger = 17
let binaryInteger = 0b10001       // 17 in binary notation
let octalInteger = 0o21           // 17 in octal notation
let hexadecimalInteger = 0x11     // 17 in hexadecimal notation

2.科学计数法

  • 1.25e2 1.25 x 10的平方
  • 0xfp-2 15 x 10的-2次方

数值类型转换

官档原文

1.整数转换

let cannotBeNegative: UInt8 = -1
// UInt8 cannot store negative numbers, and so this will report an error
let tooBig: Int8 = Int8.max + 1
// Int8 cannot store a number larger than its maximum value,
// and so this will also report an error

let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)

和其他语言一样,某类型整数表示的数不能超过它能表示的范围;其次,不同类型的两个数需要转换为相同类型再进行加减法运算。

2.浮点数与转换

let integerPi = Int(pi)

通过转换接口转换。

类型别名

官档原文

typealias AudioSample = UInt16

var maxAmplitudeFound = AudioSample.min  // means UInt16.min
// maxAmplitudeFound is now 0

就是可以给固有的数据类型起一个别名,至于用处,文档是这样描述的:

Type aliases are useful when you want to refer to an existing type by a name that is contextually more appropriate, such as when working with data of a specific size from an external source.

当你想在特定上下文通过更合适的名称来引用现有类型时,别名就显得很有用。例如从外部源处理特定大小的数据时。

what?关于这一点的设计哲学,说实话超哥不是很明白。或者只是为了代码上语义看上去更加明确和鲜明?

布尔值

官档原文

et orangesAreOrange = true
let turnipsAreDelicious = false

if turnipsAreDelicious {
    print("Mmm, tasty turnips!")
} else {
    print("Eww, turnips are horrible.")
}

基本上和OC一样,但是这里有一点需要注意。就是整数类型和布尔值的转换,在OC里if里int只要是非0值就会认为对应的布尔值为真,按真的逻辑处理。例如下面的代码可以运行的:

NSInteger i = 0-1;
    if (i) {
        
        NSLog(@"complie succ");
    }

但是,在Swift里布尔值的定义是严格的,上面的写法会提示i不是一个布尔值,因而导致编译不通过。

image.png

元组

官档原文

Tuples是一个OC里没有的概念。它的定义是这样的:

Tuples group multiple values into a single compound value. The values within a tuple can be of any type and don’t have to be of the same type as each other.

元组将多个值组合为一个复合值。其中的类型可以是任意类型,并且他们可以是不同类型。

1.🌰

let http404Error = (404, "Not Found")
// http404Error is of type (Int, String), and equals (404, "Not Found")

这个🌰的元组用来描述http状态代码。404代表错误码,"Not Found"代表错误的描述信息。将一个int和string复合为一个元组来表示http的状态信息。

2.表示和使用

//1.一般表示
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// prints "The status code is 404"
print("The status message is \(statusMessage)")
// prints "The status message is Not Found"

//2.按需使用,不用的用_代替
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// prints "The status code is 404"

//3.按索引访问
print("The status code is \(http404Error.0)")
// prints "The status code is 404"
print("The status message is \(http404Error.1)")
// prints "The status message is Not Found"

//4.为元组元素命名,按名访问
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
// prints "The status code is 200"
print("The status message is \(http200Status.description)")
// prints "The status message is OK"

方法2让我想起了go语言中数组和字典的遍历,只需要访问值不需要下标的时候也是可以使用_占位即可。

方法3说明其内部的存储类似于数组,也是一个有序的顺序结构。

Optionals类型

官档原文

这又是一个Swift特有的类型。

You use optionals in situations where a value may be absent. An optional represents two possibilities: Either there is a value, and you can unwrap the optional to access that value, or there isn’t a value at all.

optionals类型用于处理值可能缺失的情况。可选意味着:

  • 这里有一个值,并且你可以打开可选项访问他
  • 根本就不存在值

The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structures, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there’s a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants.

这一段大概是说optionals类似于OC里的nil,但是nil只能用来表示对象,不能表示一般数据类型。但optionals可以用于这些类型。

1.nil 只有optional类型才能被赋值为nil

// optional类型
var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404
serverResponseCode = nil
// serverResponseCode now contains no value

//普通int类型
var i = 345
// 这样赋值编译器会报错:can not assign to value
I = nil

2.optional类型的展开

if convertedNumber != nil {
    print("convertedNumber has an integer value of \(convertedNumber!).")
}
// prints "convertedNumber has an integer value of 123."

if let actualNumber = Int(possibleNumber) {
    print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
} else {
    print("\'\(possibleNumber)\' could not be converted to an integer")
}

4.隐式展开optional

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
 
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation mark

Sometimes it’s clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it’s useful to remove the need to check and unwrap the optional’s value every time it’s accessed, because it can be safely assumed to have a value all of the time.

有时optional类型在设置值之后,将始终拥有该值。在这个情况下,不需要每次访问都检查和解包。

使用"!"而不是"?",即隐式自动解包(将其值暴露)。实际上,这种情况就和一般变量的使用一样了。

错误处理

官档原文

本质上还是try-catch那一套。关于错误处理,后面还有专门的章节详述。

func canThrowAnError() throws {
    // this function may or may not throw an error
}

do {
    try canThrowAnError()
    // no error was thrown
} catch {
    // an error was thrown
}

断言

官档原文

断言和先决条件,这也是我们都熟悉的。他们是在运行时发生的检查,如果断言里或先决条件里的布尔值为真,则代码照常执行;否则,程序的当前状态无效,代码执行将结束。

The difference between assertions and preconditions is in when they’re checked: Assertions are checked only in debug builds, but preconditions are checked in both debug and production builds. In production builds, the condition inside an assertion isn’t evaluated. This means you can use as many assertions as you want during your development process, without impacting performance in production.

断言和先决条件的不同之处在于他们什么时候做检查:断言只在 debug 构建的时候检查,但先决条件则在 debug 和生产构建中生效。在生产构建中,断言中的条件不会被计算。这就是说你可以在开发的过程当中随便使用断言而无需担心影响生产性能。

1.断言的使用

let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
// This assertion fails because -3 is not >= 0.

if age > 10 {
    print("You can ride the roller-coaster or the ferris wheel.")
} else if age >= 0 {
    print("You can ride the ferris wheel.")
} else {
    assertionFailure("A person's age can't be less than zero.")
}

2.强制先决条件

// In the implementation of a subscript...
precondition(index > 0, "Index must be greater than zero.")

preconditionFailure("Index can't be less than zero.")

3. fatalError用于标注暂时还没实现的方法

fatalError("Unimplemented")
image.png

至此,这一节就告一段落了。

---------------------------------------------------------20190519.13.24午后

I know I want, and now I can

有时候
坚持你最不想干的事
反而能得到你最想要的东西
但是
如果可以给这种不想干
注入一种激情
那么得到的会不会更多呢?
-----------------------------非著名八线互联网九流程序猿 chaors

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

推荐阅读更多精彩内容