第一章 欢迎使用Swift

简单值

let表示常量,var表示变量,
不用声明类型,编译器自动判断。也可以在变量后面加冒号声明属性
也不用写分号。

var myVariable = 42
myVariable = 50
let myConstant = 42
let explicitDouble: Double = 70

将数强制转换为字符串:

let label = "aaa"
let width = 94
let widthStr = label+String(width)
print(widthStr)
//打印结果:aaa94

使用\()也可以将值转为字符串:

let number1 = 3
let number2 = 5
let appleSum = "I have \(number1+number2) apples"
print(appleSum)
//打印结果:I have 8 apples

使用方括号[]来创建数组和字典,最后一个元素后面允许有个逗号。

var lists = ["111", "222", "333"]
lists[0] = "444";
print(lists)
        
var dic = ["key1":"aaa", "key2":"bbb"]
dic["key3"] = "ccc";
print(dic)

//打印结果:
//["444", "222", "333"]
//["key2": "bbb", "key3": "ccc", "key1": "aaa"]

创建空数组和空字典,可以存基本类型.

var emptyArray = [Int]()
emptyArray = [124]
print(emptyArray)

var emptyDic = [String: Float]()
emptyDic = ["key" : 23]
print(emptyDic)
//打印结果:
//[124]
//["key": 23.0]

若信息可以推断出来,也可以这么初始化:

Lists = []
Dic = [:]

控制流

  • if、switch、for、while等语句的括号都可以省掉:
        let scores = [100, 99, 88, 50, 70]
        var teamScore = 0
        for obj in scores {
            if obj>60 {
                teamScore += 3
            } else {
                teamScore -= 1
            }
        }
  • if 后面必须是个布尔表达式,如 if score 会报错,不会默认和0对比。。

  • 使用 ??来提供一个默认值。如果可选值缺失的话,可以使用默认值来代替。

let aaa: String? = "aaa"
let bbb: String = "bbb"
let ccc = "hi \(aaa ?? bbb)"
print(ccc)
//若aaa不为空,打印hi aaa, 否则打印hi bbb
  • switch的用法:不用写break。
let aaa: String = "abbb"
switch aaa {
case "aaa":
    print("aaa")
case "bbb":
    print("bbb")
case let x where x.hasSuffix("b"): // let 将匹配等式的值赋给常量 x
    print("ccc");
default:
    print("other")
}
  • 使用 for-in 遍历字典和数组。(PS: []既可以表示字典又可以表示数组)
let dic = [
    "key1" : [1, 2, 3],
    "key2" : [4, 5, 6]
]

for (key, arrs) in dic
{
    for number in arrs {
        print("结果是 \(number)")
    }
}
  • 在循环中使用 ..< 来表示范围,相当于<。而...相当于<=
for i in 0..<4 { // 竟然不用声明 i 的类型
    print(i)
}
//打印结果是 0 1 2 3

若换成 ... 则是打印 0 1 2 3 4
for i in 0...4 {
    print(i)
}
//打印结果是 0 1 2 3 4

函数和闭包

  • func 声明函数,->指定返回值类型
  • 多个参数间用,号隔开
func getInfo(name: String, age: Int) ->String {
    return "Info:\(name), \(age)"
}
print(getInfo(name: "laoyue", age: 12))
  • 参数前面加 _,调用时可以隐藏参数名。
func getInfo(_ name: String, _ age: Int) ->Void {  
    print("Info:\(name), \(age)")
}
getInfo("laoyue", 12)
  • 使用元组来让一个函数返回多个值。该元组的元素可以用名称或数字来表示。
func abc(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var mi = scores[0]
var ma = scores[0]
var s = 0
for score in scores {
    if score>ma {
        ma = score
    }
    else if score<mi {
        mi = score;
    }
    s += score
}
return (mi, ma, s)
}
  • 不定参数的函数
func sum(scores: Int...) -> Void {
    var sum: Int = 0;
    for score in scores {
        sum += score
    }
    print(sum)
}

sum(scores: 1, 2, 3, 4, 5)
  • 函数内部可以嵌套另一个函数。被嵌套的函数可以访问外侧函数的变量, 你可以使用嵌套函数来重构一个太长或者太复杂的函数。
    func printSumScore(scores: [Int]) -> Void {
        var sumScore = 0;
        func sum(scores: [Int])->Int {
            for score in scores {
                sumScore += score
            }
            return sumScore
        }
        print(sumScore);
    }
  • 函数是第一等类型,这意味着函数可以作为另一个函数的返回值。(没太看懂)
func makeIncrementer() -> ((Int) -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()
increment(7)
  • 函数可以作为另一个函数的返回值。
func makeIncrementer() -> ((Int) -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne   
    //这里是将整个函数作为返回值返回,所以 makeIncrementer 函数的返回值是 `(Int) -> Int`,就是addOne函数的类型
}
var increment = makeIncrementer()
increment(7)
  • 函数可以作为另一个函数的参数。conditon后面的参数类型是函数。
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
    for item in list {
        if condition(item) {
            return true
        }
    }
    return false
}
func lessThanTen(number: Int) -> Bool {
    return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)
  • 闭包那块内容没看懂。。。

对象和类

  • 创建一个类
class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}
  • 创建一个类的实例,在类名后面加上括号。使用点语法来访问实例的属性和方法。
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
  • init 方法,self用来区分属性和参数。
class NamedShape {
    var numberOfSides: Int = 0
    var name: String

    init(name: String) {
        self.name = name
    }

    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}
//此处若用 var 会警告,因为xcode未检测到 namedShape 有变化,认为其为常量
let namedShape = NamedShape(name: "laoyue")
  • override覆写父类方法
class Square: NamedShape {
    var sideLength: Double

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }

    func area() ->  Double {
        return sideLength * sideLength
    }

    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
  • 属性的 settergetter 方法,必须同时实现,不能只实现其中的一个。
class EquilateralTriangle: NamedShape {//等边三角形
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength  //1.设置子类声明的属性值
        super.init(name: name)        //2.调用父类的构造器
        numberOfSides = 3             //3.改变父类定义的属性值。其他的工作比如调用方法、getters 和 setters 也可以在这个阶段完成。
    }

    var perimeter: Double {//周长属性,自己实现了getter、setter方法
        get {
            return 3.0 * sideLength
        }
        set {
            sideLength = newValue / 3.0  //该处的 newValue 就是传进来的值,是个隐性参数
        }
    }

    override func simpleDescription() -> String {
        return "An equilateral triangle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)
  • 普通 getter 和 setter 方法,要定义两个属性。
class MyClass {
    var _info: String = ""
    var info: String {
        get {
            return _info
        }
        set {
            _info = newValue  //newValue为隐性参数
        }
    }
}

let mycalss = MyClass()
mycalss.info = "test";
print(mycalss.info);
  • 若不需要重写 setter 和 getter方法,只是希望在赋值时执行某个任务,可以用 willSetdidSet,分别表示赋值前后。
class MyClass {
    var _info: String?
    var info: String? {
        willSet {
            print("willSet");
        }
        didSet {
            print("didSet");
        }
    }
}

let mycalss = MyClass()
print("----------")
mycalss.info = "test";
print("----------")

//打印结果:
----------
willSet
didSet
----------
  • 处理变量的可选值时,可以加?。方法也同样可以加。
let mycalss: MyClass? = MyClass()
let myname = mycalss?.name  //意思是若 mycalss 为空,则后面的就不执行了,整个返回为空。若不为空才执行

枚举和结构体

  • 枚举里可以添加方法
enum Rank: Int {
    case ace = 1
    case jack, queen, king
    func simpleDes() -> String {
        switch self {
        case .ace:
            return "ace"
        case .jack:
            return "jack"
        case .queen:
            return "queen"
        default:
            return String(self.rawValue)
        }
    }
}

let jackRawValue = Rank.jack.rawValue
print("\(jackRawValue), \(Rank.jack)")   //直接打印是字符串,打印rawValue才是Int类型的值
//打印结果:
2, jack
enum Suit {
    case spades, hearts, diamonds, clubs
    func simpleDescription() -> String {
        switch self {
        case .spades:
            return "spades"
        case .hearts:
            return "hearts"
        case .diamonds:
            return "diamonds"
        case .clubs:
            return "clubs"
        }
    }
}
let hearts = Suit.hearts
let heartsDescription = hearts.simpleDescription()
  • 注意在上面的例子中用了两种方式引用 hearts 枚举成员:给 hearts 常量赋值时,枚举成员 Suit.hearts 需要用全名来引用,因为常量没有显式指定类型。在 switch 里,枚举成员使用缩写 .hearts 来引用,因为 self 已经是一个 suit 类型,在已知变量类型的情况下可以使用缩写。

  • 如果枚举成员的实例有原始值,那么这些值是在声明的时候就已经决定了,这意味着不同的枚举成员总会有一个相同的原始值。当然我们也可以为枚举成员设定关联值,关联值是在创建实例时决定的。这意味着不同的枚举成员的关联值都可以不同。你可以把关联值想象成枚举成员的寄存属性。例如,考虑从服务器获取日出和日落的时间。服务器会返回正常结果或者错误信息。

enum ServerResponse {
    case result(String, String)
    case failure(String)
}
let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")

switch success {
case let .result(sunrise, sunset):
    print("Sunrise is at \(sunrise) and sunset is at \(sunset)")
case let .failure(message):
    print("Failure...  \(message)")
}
  • 注意日升和日落时间是如何从 ServerResponse 中提取到并与 switch 的 case 相匹配的。

  • 结构体。结构体和类有很多相同的地方,比如方法和构造器。它们之间最大的一个区别就是结构体是传值,类是传引用。

struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .three, suit: .spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()

协议和扩展

protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}
class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A very simple class."
    var anotherProperty: Int = 69105
    func adjust() {
        simpleDescription += "  Now 100% adjusted."
    }
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription

struct SimpleStructure: ExampleProtocol {
    var simpleDescription: String = "A simple structure"
    //mutating 关键字用来标记一个会修改结构体的方法。SimpleClass 的声明不需要标记任何方法,因为类中的方法通常可以修改类属性(类的性质)。
    mutating func adjust() {
        simpleDescription += " (adjusted)"
    }
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
  • 下面是给Int类型增加扩展,可增加新的方法和属性。
extension Int: ExampleProtocol {
    var simpleDescription: String {
        return "The number \(self)"
    }
    mutating func adjust() {
        self += 42
    }
}
print(7.simpleDescription)
  • 你可以像使用其他命名类型一样使用协议名——例如,创建一个有不同类型但是都实现一个协议的对象集合。当你处理类型是协议的值时,协议外定义的方法不可用。
let protocolValue: ExampleProtocol = a
print(protocolValue.simpleDescription)
// print(protocolValue.anotherProperty)  // 去掉注释可以看到错误
  • 即使 protocolValue 变量运行时的类型是 simpleClass ,编译器还是会把它的类型当做ExampleProtocol。这表示你不能调用在协议之外的方法或者属性。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • Hello Word 在屏幕上打印“Hello, world”,可以用一行代码实现: 你不需要为了输入输出或者字符...
    restkuan阅读 3,144评论 0 5
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young阅读 3,766评论 1 10
  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,125评论 9 118
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,563评论 18 139
  • 这一篇比较偏重于功能介绍,具体的实例操作请参考其他文章:未完成 游戏场景中灯光照明的构成 现实生活中的光线是有反射...
    shimmery阅读 53,333评论 6 58