Swift 温故知新

仔细想了想,我学swift的时候还是我刚接触ios开发的时候了,那时swift还是beta版,当时因为考虑到时beta版,有许多东西经常变,还没有定论,所以就没有投入过多的精力去学习,后来工作也一直用object-c,没有用到swift,所以swift算是荒废了好久了。现在swift正式版本都已经出了好多版本了,已经有很多公司在用swift开发了项目了,所以觉得很有必要重新学习下swift,好好感受下这门新语言的魅力!

以下是本人阅读swift文档之后总结整理的一些知识点,以及一些个人觉得swift和object-c的不同之处和个人理解,如有解释不到位或是有误的地方,还请各位指出,大家相互学习!

//

//  main.swift

//  SwiftLearning

//

//  Created by kenny on 17/6/6.

//  Copyright © 2017 kenny. All rights reserved.

//


import Foundation


//swift 的语句末尾的;号是非必要的了,可有可无,和JavaScript一样

let label = "The width is "

let width = 94

let widthLabel = label + String(width)//相比object-c字符串也可以直接相加得到另一个字符串了

let labelWidth = "the width is \(width)"//对于intfloatdouble等基本数据类型可以通过\()进行拼接


let singleString = "single string"


//使用“”“ ”“” 引用的字符串可以换行了,不过这是swift4的特性,我目前的xcode8.1的,对应的swift3版本,以下注释代码会报错

//let quotation = """

//Even though there's whitespace to the left,

//the actual lines aren't indented.

//Except for this line.

//Double quotes (") can appear without being escaped.

//

//I still have \(apples + oranges) pieces of fruit.

//""";


//创建并初始化数组

var shoppingList = ["catfish", "water", "tulips", "blue paint"]

shoppingList[1] = "bottle of water"

//创建并初始化字典

var occupations = [

    "Malcolm": "Captain",

    "Kaylee": "Mechanic",

]

occupations["Jayne"] = "Public Relations"

//如果数组和字典的类型可以被推断出来则可以通过以下方式设为新的空对象,但是不能作为初始化方法,如:var shoppingList = []var occupations = [:]是不行的,必须指明数据类型

shoppingList = []

occupations = [:]


//通过构造函数创建一个空的指明类型的数组或字典

let emptyArray = [String]()

let emptyDictionary = [String: Float]()


//for循环和if语句更简洁了,省略了括号,另外不能直接用if (a)这样的形式来判断对象是否为空了,因为if后面必须为bool类型,不过可以通过let a = b的形式来判断b对象是否为空,因为bnil的话会返回false,当然a==nil的形式肯定没有问题

let individualScores = [75, 43, 103, 87, 12]

var teamScore = 0

for score in individualScores {

    if score > 50 {

        teamScore += 3

    } else {

        teamScore += 1

    }

}


/*for循环可以循环字典了,JavaScript也可以for循环字典,不过只是遍历字典的key而已,如下输出的只是key而已:

 var dic = {"key":"kenny", "key1":"xiayu"}

 for (i in dic)

 {

 console.log(i)

 }

key

key1

 */

let interestingNumbers = [

    "Prime": [2, 3, 5, 7, 11, 13],

    "Fibonacci": [1, 1, 2, 3, 5, 8],

    "Square": [1, 4, 9, 16, 25],

]

var largest = 0

for (kind, numbers) in interestingNumbers {

    for number in numbers {

        if number > largest {

            largest = number

        }

    }

}

print(largest)


//for循环还可以如下这样写,这里循环4次,分别是0123

var total = 0

for i in 0..<4 {

    total += i

}

print(total)//输出结果为6


var optionalString: String?//初始化一个可为空string类型的变量,当然其他类型的变量也可以

print(optionalString == nil)

//对于可选变量进行方法调用,如对象为nil则不会执行,这一定程度上提高了代码的健壮性

optionalString?.append("a")



var optionalName: String?

var greeting = "Hello!"

//这样可以判断一个对象是否为nil,和==nil左右一样

if let name = optionalName {

    greeting = "Hello, \(name)"

    print(greeting)

}

else {

    print(greeting)

}


//??判断前面的变量值是否为nil,是的话使用??后面的值,和三目运算符类似,C#中也有该特性,用法和这个一样

let nickName: String? = nil

let fullName: String = "John Appleseed"

let informalGreeting = "Hi \(nickName ?? fullName)"


//switch变得很强大了,不仅仅只支持integer类型了,也不仅仅用于判断是否相等了,不需要break了,不过default分支是必须的,这极大程度的加强了switch的语法并加强了switch语句的功能性,具体用法如下:

let vegetable = "red pepper"

switch vegetable {

case "celery":

    print("Add some raisins and make ants on a log.")

case "cucumber", "watercress":

    print("That would make a good tea sandwich.")

case let x where x.hasSuffix("pepper"):

    print("Is it a spicy \(x)?")

default:

    print("Everything tastes good in soup.")

}


let arrary = ["a", "b"]

switch arrary {

case let x where x.count == 0:

    print("funny")

default:

    print("default")

}


//while do...while改成了如下形式

var n = 2

while n < 100 {

    n *= 2

}

print(n)


//do换成了repeat

var m = 2

repeat {

    m *= 2

} while m < 100

print(m)


//方法定义需要用到func关键字了,具体初始化形式如下:

func greet(person: String, day: String) -> String {

    return "Hello \(person), today is \(day)."

}

print(greet(person: "kenny", day: "2017-06"))


//以下定义形式参数输入提示变成了这样 greet(<#T##person: String##String#>, on: <#T##String#>),

func greet(_ person: String, on day: String) -> String {

    return "Hello \(person), today is \(day)."

}


//Oject-c之前并不支持函数有多个返回值,只能通过字典了替换实现,现在swift支持多个返回值了,如下:

func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {

    var min = scores[0]

    var max = scores[0]

    var sum = 0

    

    for score in scores {

        if score > max {

            max = score

        } else if score < min {

            min = score

        }

        sum += score

    }

    

    return (min, max, sum)

}

let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])

//换取对应返回值的方式有以下两种,可以通过返回变量名获取下标

print(statistics.sum)

print(statistics.2)


//支持了函数嵌套,嵌套方法的好处就是方便代码的整合和管理,需要注意的是被嵌套的函数属于私有方法,不支持外部调用

func returnFifteen() -> Int {

    var y = 10

    func add() {

        y += 5

    }

    add()

    return y

}

let result = returnFifteen()


//函数也可以作为返回值返回,返回值可以直接调用,是一个挺强大的功能,代码的设计方式有多了几分可变性

func makeIncrementer() -> ((Int) -> Int) {

    func addOne(number: Int) -> Int {

        return 1 + number

    }

    return addOne

}

var increment = makeIncrementer()

let result1 = increment(7)


//函数也可以作为参数传入

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]

let result3 = hasAnyMatches(list: numbers, condition: lessThanTen)


//可以直接传一个函数闭包

let result4 = numbers.map({ (number: Int) -> Int in

    let result = 3 * number

    return result

})


//如果已知需要传入的函数的参数类型和返回类型甚至可以省略参数和返回值的类型,对于单语句闭包隐式返回它们唯一语句的值。可做如下简化

var mappedNumbers = numbers.map({ number in 3 * number })

//一个闭包作为函数的最后一个参数可以在括号之后立即出现。如:

mappedNumbers = numbers.map(){number in 3 * number}

//当闭包是函数的惟一参数时,可以完全省略括号。还可以省略参数名,直接根据数字来引用每个参数($0$1$2......

let sortedNumbers = numbers.sorted { $0 > $1 }//从大到小排序

//还可以进一步简化,你敢信?以下排序结果同上,不过过度简化会使可读性下降,个人觉得不应该太过追求简化

let numbersSorted2 = numbers.sorted(by: >)


//类的声明,对象的实例化,以及属性及方法的调用

class Shape {

    var numberOfSides = 0

    func simpleDescription() -> String {

        return "A shape with \(numberOfSides) sides."

    }

}

//无论是属性的设置和访问还是方法的调用现在都是用.语法了

var shape = Shape()

shape.numberOfSides = 7

var shapeDescription = shape.simpleDescription()


class NamedShape {

    var numberOfSides: Int = 0

    var name: String

    //构造函数

    init(name: String) {

        self.name = name

    }

    func simpleDescription() -> String {

        return "A shape with \(numberOfSides) sides."

    }

}

//继承及多态特性

class Square: NamedShape {

    //设置器和访问器写法

    var length:Double

    var perimeter: Double {

        get {

            return 3.0 * length

        }

        set {

            length = newValue / 3.0

        }

    }

    //还可以通过willsetdidset要控制参数的设置,比如说为电话号码加前缀去前缀等

    var triangle: Double {

        willSet {

            length = newValue * 3

        }

        didSet {

            length /= 3

        }

    }

    

    var sideLength: Double

    

    init(sideLength: Double, name: String) {

        /*

         A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.”

          the memory for an object is only considered fully initialized once the initial state of all of its stored properties is known. In order for this rule to be satisfied, a designated initializer must make sure that all of its own properties are initialized before it hands off up the chain.

         

         An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.

         The class instance is not fully valid until the first phase ends. Properties can only be accessed, and methods can only be called, once the class instance is known to be valid at the end of the first phase.

         */

        //在调用super.init之前自身的属性必须要有个默认值,因为只有所有的属性都有值了才可以allocate内存

        //至于为什么super.init之前可以通过self.xx访问属性,个人猜想是因为这个时候self已经构建出来了,并且这几个属性并没有设置器和访问器,不存在访问父类属性的可能,所以允许通过self.xx访问属性

        self.length = 0

        self.triangle = 0

        self.sideLength = sideLength

        super.init(name: name)

        self.perimeter = 0//而对于有设置器和访问器的属性需要放在super.init后面,因为文档指出只有调用了super.init才算初始化完,我个人认为为了防止在设置器访问器访问未初始化好的父类属性,所以禁止了该操作

        numberOfSides = 4

    }

    

    func area() -> Double {

        return sideLength * sideLength

    }

    //重写父类方法

    override func simpleDescription() -> String {

        return "A square with sides of length \(sideLength)."

    }

}


//新的枚举,支持枚举内定义方法,获取枚举的keyvaluec#也支持,object-c是不支持的

enum Rank: Int {

    case ace = 1

    case two, three, four, five, six, seven, eight, nine, ten

    case jack, queen, king

    func simpleDescription() -> String {

        switch self {

        case .ace:

            return "ace"

        case .jack:

            return "jack"

        case .queen:

            return "queen"

        case .king:

            return "king"

        default:

            return String(self.rawValue)

        }

    }

}

let ace = Rank.ace

let aceRawValue = ace.rawValue

let r = Rank.init(rawValue: 1)//使用枚举构造函数可以获取对应值的枚举,这里获取到的结果和let ace = Rank.ace一样

print(aceRawValue)


//枚举还有这种传参用法,惊咯!!!!

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)")

}


//结构体,也支持内部定义方法

struct Card {

    var suit: Rank

    var rank: Rank

    func simpleDescription() -> String {

        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"

    }

}

let threeOfSpades = Card(suit: .jack, rank: .ace)

let threeOfSpadesDescription = threeOfSpades.simpleDescription()


//协议,枚举,结构体,类均可以遵循协议,需要注意的是结构体遵循协议时需要在方法前面加mutating关键字表明该方法是可继承修改的,而类并不需要,因为类的方法都是可以继承修改的

protocol ExampleProtocol {

    var simpleDescription: String { get }

    mutating func adjust()

}


//延展

extension Int: ExampleProtocol {

    var simpleDescription: String {

        return "The number \(self)"

    }

    mutating func adjust() {

        self += 42

    }

}

print(7.simpleDescription)


//异常处理

enum PrinterError: Error {

    case outOfPaper

    case noToner

    case onFire

}


func send(job: Int, toPrinter printerName: String) throws -> String {

    if printerName == "Never Has Toner" {

        throw PrinterError.noToner

    }

    return "Job sent"

}


do {

    let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")

    print(printerResponse)

} catch {

    print(error)

}


//catch 可以区分各种异常

do {

    let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")

    print(printerResponse)

} catch PrinterError.onFire {

    print("I'll just put this over here, with the rest of the fire.")

} catch let printerError as PrinterError {

    print("Printer error: \(printerError).")

} catch {

    print(error)

}


//也可以使用try?来捕获异常,当抛出异常时,值为nil

let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")

let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")


var fridgeIsOpen = false

let fridgeContent = ["milk", "eggs", "leftovers"]


//在方法里面可以写defer块做一些必要的处理,defer里面的代码不管是否异常都会执行

func fridgeContains(_ food: String) -> Bool {

    fridgeIsOpen = true

    defer {

        fridgeIsOpen = false

    }

    

    let result = fridgeContent.contains(food)

    return result

}

let res = fridgeContains("banana")

print(fridgeIsOpen)


//泛型,方法,类,枚举,结构体均可以使用泛型

func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {

    var result = [Item]()

    for _ in 0..<numberOfTimes {

        result.append(item)

    }

    return result

}

let v = makeArray(repeating: "knock", numberOfTimes: 4)


//使用where限制泛型的条件

func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool

    where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {

        for lhsItem in lhs {

            for rhsItem in rhs {

                if lhsItem == rhsItem {

                    return true

                }

            }

        }

        return false

}

let resu = anyCommonElements([1, 2, 3], [3])


以上便是本人这几天对swift的学习内容,如有解释错误或不到位的地方,请指出,谢谢!


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值