Swift入门基础1——元组、可选类型和循环

前言

本来之前计划是11月份开始学习Swift语言的,但是前段时间项目赶进度,加班厉害。所以计划没启动几天就搁置了,现在终于闲了下来,可以好好开始学习学习Swift了。Swift从苹果推出至今,已经出现了好几次比较大的版本更新,现在是Swift 3.0了,语法趋于稳定。而且Swift语言更简洁,更安全,更强大。它应该会越来越流行,最终取代OC作为iOS开发的第一语言。作为开发人员应当保持学习的激情,紧跟技术更新,不断学习积累。in one word,up or out.


元组

元组是OC中没有的一种新数据结构,它有点将数组和字典揉合的感觉,既像数组也像字典,使用起来极其灵活。
元组的初始化和使用都极其灵活,下面是些例子:

初始化时不申明元组类型,赋值时不申明元素名字。
此时则类似数组,可通过索引访问各个元素。但元组和数组不同的是,数组各项元素的类型必须一致,而元组不是,它的元素可以是任意类型。

        let a = ("wang66", "wangpsd", true)
        print("a---\(a)")
        print("a---\(a.0)")
        print("a---\(a.1)")
        print("a---\(a.2)")

初始化时申明元组类型,但赋值时不申明元素名字:
此时仍类似数组。只不过申明元组类型(各元素类型)使其看起来更清晰。

        let aa: (String, String, Bool) = ("wang66", "wangpsd", true)
        print("aa---\(aa)")
        print("aa---\(aa.0)")
        print("aa---\(aa.1)")
        print("aa---\(aa.2)")

初始化时不申明元组类型,但赋值时申明元素名字。
此时则类似字典,通过元素名字可访问其值。

        let b = (name:"wang66", passwd:"wangpsd", isLogin:true)
        print(b)
        print(b.name)
        print(b.passwd)
        print(b.isLogin)

初始化时申明元组类型,且赋值时申明元素名字

        let bb: (String, String, Bool) = (name:"wang", passwd:"wang", isLogin:true)
        print(bb)
        print(bb.0)
        print(bb.1)
        print(bb.2)

初始化时申明元素类型,且在元素类型里申明了元素名字。而且在赋值时带上了元素名字。

        let bbb: (name:String, passwd:String, isLogin:Bool) = (name:"wang", passwd:"wang", isLogin:false)
        print(bbb)
        print(bbb.0)
        print(bbb.passwd)
        print(bbb.isLogin)

初始化时申明元素类型,且在元素类型里申明了元素名字。但在赋值时没有写元素名字。
此时,仍旧可以通过元素名字得到值。

        let bbbb: (name:String, passwd:String, isLogin:Bool) = ("wang", "wang", false)
        print(bbbb)
        print(bbbb.name)
        print(bbbb.passwd)
        print(bbbb.isLogin)

还可以将元组当作一些变量/常量的合集来使用:

        let (name, passwd, isLogin) = ("wang", "wang", true)
        print(name)
        print(passwd)
        print(isLogin)
何处该用元组?

当你想让你的方法返回多个类型的多个值时,这是元组的最佳使用场景。如果返回的多个值类型是一致的,以往我们使返回类型为一个字典。但是若返回的多个值为不同的类型,以往我们可以将其封装为一个model,而有些时候感觉就几个数据并没有必要封装为model。在Swift中,元组可以完美地解决这个问题。

    func getStudentInfo() -> (name: String, age: Int, isPass: Bool) {
        let stuInfo = (name:self.stuName, age:self.stuAge, isPass: self.isPass)
        return stuInfo
    }

可选类型

可选类型(optionals),也是Swift的新特性。它表示** 可以有值,也可以没值;有值时为x,没值时便为nil。**
OC中也有nil,但是那只适用于对象,而Swift的可选类型却是适用于所有类型的,包括基本数据类型。

Swift之所以引进可选类型,主要是为了提高安全性。因为在代码中经常有些“未预期的变量为空”情况,在有些情况下很可能会程序crash掉,存在很大安全隐患。我们在写代码时为了避免出现这种安全问题,常常在代码中写入了了大量“防崩代码”,在调用方法前先判断调用者是否为空,在定义的方法内部判断参数是否为空等。
Swift就此做了努力,使这些可能为空的变量,在编译器编译时不予通过,将隐患扼杀在摇篮里。

下面先申明了一个字符串,但是没有初始化,然后打印该字符串。编译报错:❌variable 'str' used before being initialized。告诉我们str没有赋初值。

        var str: String
        print(str)

而我们将该字符串申明为可选类型后,便不会报错了。打印结果为nil。

        var str: String?
        print(str)

可选类型的拆包

Optional类型的值不能被直接使用,当需要用时要“拆包”,拆包有“显式拆包”“隐式拆包”

显式拆包:

所谓显式拆包,就是当变量用?申明未可选变量后。在使用变量时需要使用!来拆包, 获得它的值。

        var str: String? = "wang66"
        print(str!)

但这样一点也不安全,假如该str申明后没有被赋初值就拆包的话,编译可以通过,但是运行时会报错:❌unexpectedly found nil while unwrapping an Optional value

所以我们应当用if语句判断str,不为空时才进行拆包取值。注意:!=两侧都必须有空格,不然编译会报错:❌'=' must have consistent whitespace on both sides

        var str: String?
        if str != nil {
            print(str!)
        }else{
            print("str is nil")
        }
可选绑定:

像上面那样看起来不错了,但是也不完美。因为你在每次使用该变量时都被要求进行拆包。(虽然编译不会报错,但没有拆包,拿不到正确的值。会打印:Optional("1234"))。这是何其麻烦。

        var str: String?
        str = "1234"
        if str != nil {
            print(str!)
            print("str=\(str!)")
        }else{
            print("str is nil")
        }

为了避免每次使用变量时都要拆包,Swift引进了“可选绑定”:在if后面将可选变量赋给一个临时量,Swift会自动检测其是否包含值。若包含,则隐式拆包。那我们在后续便可以直接使用这个临时量了。
这个临时量既可以时常量let,也可以是变量var

        var str: String?
        str = "1234"
        if let tempStr = str{ // 将str赋给一个临时量,Swift会自动检测其是否包含值。若包含,则隐式拆包。
            print(tempStr)
        }
隐式可选类型的隐式拆包:

上面我们说了在申明变量/常量时,在类型后面加?表明它是个可选变量/常量。其实,Swift中还可以在类型后面加!,这代表什么呢?这代表它是个“隐式可选类型”。它是个可选类型,但是是隐式的。何谓隐式?就是我们在使用这个变量时就已确定它被初始化,不为nil了。我们每次直接使用变量,编译器会自动帮我们拆包。

        let str: String! = "wang66"
        print(str)

除非你真的确定你的变量已被初始化,不为nil。否则不要轻易使用“隐式拆包”,它也是有隐患的。
下面的代码也会报上面出现的错误:❌unexpectedly found nil while unwrapping an Optional value
str被置为nil了,然后编译器在自动拆包时,便蒙逼crash了。

        var str: String! = "wang66"
        str = nil
        print(str)
可选链式调用:

首先链式调用我们都知道,但是因为在Swift中有可选类型,这就导致了如果链式调用的某个环节,某个属性值为nil,某个方法返回值为nil,如果继续往链后面调用的话,会出问题的。所以为了避免这个问题,Swift是这样处理的。

class UserModel: NSObject {
    var userName: String?
    var address: String?
    var book: BookModel?
    func buy() {
        print("userName:\(userName), address:\(address), bookName:\(book?.bookName), price:\(book?.price)")
    }
}
class BookModel: NSObject {
    var bookName: String?
    var price: Double?
    func bookDesc() {
        print("bookName:\(bookName), price:\(price)")
    }
}

上面定义了两个类UserModelBookModel。两个类中的属性均为可选的,即有可能是空的。UserModel中的属性之一是BookModel类型的book。我们创建UserModel的实例user来通过链式语法来读写book属性。Xcode会自动帮我们在链中可能为nil的某实例后自动加上?作为处理,当非nil时,沿着链继续往后调用;若为nil,则返回nil,链式调用终止。

        let user = UserModel()
        user.book = BookModel()
        user.book?.bookName = "wanger"
        user.book?.price = 41.0
        user.book?.bookDesc()
        print("bookName:\(user.book?.bookName!)")

for-in循环

当我在swift中写出一个经典的for循环时,编译器报错了❌,而且是两个错误:
1.'++' is unavailable: it has been removed in Swift 3; 自增语法在swift3上废除了。
2.C-style for statement has been removed in Swift 3 C风格的循环写法在Swift3上废除了。

        let arr = ["wang11", "wang22", "wang33", "wang44"]
        
        for var i=0; i<10; i++
        {
            print(arr[i])
        }

看来循环语句不能这么写了。Swfit语句中只有for-in循环,但它完全够用了,可以取代经典的C写法。

        let arr = ["wang11", "wang22", "wang33", "wang44"]
        for item in arr {
            print(item)
        }

之所以说它可以取代C写法的for循环,是因为还可以这么写。(0...arr.count-1)“闭区间操作符”index的值在for循环执行的过程中,从闭区间的第一位取值,直到闭区间最后一位时循环结束。

        let arr = ["wang11", "wang22", "wang33", "wang44"]
        for index in (0...arr.count-1) {
            print(arr[index])
        }

(0...x)之所以叫闭区间,是因为首尾值都包括在内。Swift也提供了“半开半闭区间”(0..<x),是前闭后开的。还是上面的例子:

        let arr = ["wang11", "wang22", "wang33", "wang44"]
        for index in (0..<arr.count) {
            print(arr[index])
        }

遍历字典的情况:将遍历出的每项字典元素赋给一个临时元组,后续使用时从元组中取值。

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

推荐阅读更多精彩内容