Swift 2.2 语法 (中)

前言:
1.此文中的语法会根据Swift的升级变动而更新。
2.如果需要请移步 -> swift2.2 语法(上)swift 2.2语法(下)

函数

  • 和C语言一样,swift也有函数,性质和我们熟悉的Objective-C的方法相当

  • 格式:


    func 函数名(参数列表) -> 返回值类型 {
        代码块
        //  如果设置了返回值类型,就需要返回相应的返回值
        return 返回值
    }
    
    
    • func是swift内的关键字,参数列表内多个参数之间用 "," 隔开,可以没有参数
    • "->" 指向返回值类型
    • 当然,如果函数没有返回值(返回值为Void),那么 "-> 返回值类型" 这部分可以省略不写(默认就是没有返回值)
  • 函数几种定义方式:

    //  定义没有参数,没有返回值的函数
    
    //  标准写法
    func test1() -> Void {
        print("没有参数没有返回值的函数")
    }
    //  简写方式一
    func test2() -> () {
        print("没有参数没有返回值的函数")
    }
    //  简写方式二
    func test3() {
        print("没有参数没有返回值的函数")
    }
    
    //  定义有参数,没有返回值的函数
    
    //  标准写法
    func test1(num : Int) -> Void {
        print("有参数没有返回值的函数")
    }
    //  简写方式一
    func test2(num : Int) -> () {
        print("有参数没有返回值的函数")
    }
    //  简写方式二
    func test3(num : Int) {
        print("有参数没有返回值的函数")
    }
    
    //  定义没有参数,有返回值的函数
    
    //  标准写法
    func test1() -> Int {
        return 0
    }
    
    //  定义有返回值,有参数的函数
    
    //  标准写法
    func test1(num1 : Int, num2 : Int) -> Int {
        return num1 + num2
    }
    
    //  定义一个有参数,且有多个返回值的函数
    
    //  标准写法
    func test1(nums : [String]) -> (strCount : Int, spellString : String) {
    
        var strCount = 0
        var spellString = ""
    
        for num in nums {
            strCount++
        
            spellString = spellString + num
        }
    
        return (strCount, spellString)
    }
    //  调用函数
    print(test1(["abc", "def", "ghi"]))
    
    
  • 函数的外部参数和内部参数

    • 内部参数:在函数内部可以看到的参数
    • 外部参数:在函数外面可以看到的参数
    • 从第二个参数开始,参数名称即是内部参数也是外部参数(默认)


    //  先来定义一个拥有多个参数的函数
    func test1(num1 : Int, num2 : Int, num3 : Int) -> Void {
        print(num1, num2, num3)
    }
    
    //  在调用函数的时候可以看下区别
    /*
    *  第一个函数没有跟上我们定义参数时所给的标签
    *  后面的所有函数都有我们定义参数时所给的标签
    *  原因:从第二个参数开始,参数名称即是内部参数也是外部参数(默认)
    *  也就是说第一个参数默认为内部参数,所以不会显示标签
    */
    test1(5, num2: 6, num3: 7)
    
    
    • 如果第一个参数也想有外部参数,可以设置标签:在变量名前增加标签


    //  先来定义一个拥有多个参数的函数,但是这次我们要让第一个参数也有外部参数
    
    func test1(num1 num1: Int, num2 : Int, num3 : Int) -> Void {
        print(num1, num2, num3)
    }
    
    //  现在再调用函数可以看到第一个参数也变拥有外部参数
    test1(num1: 5, num2: 6, num3: 7)
    
    
    • 在参数名称前加 "_" ,表示不需要外部参数


    //  先来定义一个拥有多个参数的函数,这次我们让所有参数都为内部参数
    
    func test1 (num1 : Int, _ num2 : Int, _ num3 : Int) -> Void {
        print(num1, num2, num3)
    }
    
    //  现在调用函数就会发现所有的参数都成为内部参数了
    test1(5, 6, 7)
    
    
  • 函数重载

    • 函数名称相同,但参数不同,可以称为函数重载
    • 参数拥有内部参数或外部参数不同,也被认定为参数不同


    //  函数重载例:定义三个函数,函数名相同但函数的参数不同
    
    //  无返回值,第一个参数为内部参数,第二个参数同时拥有外部和内部参数
    func test(num1 : Int, num2 : Int) -> Void {
        print("第一个函数")
    }
    
    //  无返回值,且都同时没有外部参数
    func test(num1 : Int, _ num2 : Int) -> Void {
        print("第二个函数")
    }
    
    //  无返回值,但同时拥有外部和内部参数
    func test(num1 num1 : Int, num2 : Int) -> Void {
        print("第三个函数")
    }
    
    //  调用函数
    test(1, num2: 2)
    test(1, 2)
    test(num1: 1, num2: 2)
    
    
  • 默认参数

    • 在一些特定情况下,调用函数时如果没有传入具体参数,可以使用默认参数代替(相当于我们在定义参数时就给参数一个默认值)
    //  默认参数
    
    func test(num : Int = 5) -> Int {
    
        return num
    }
    
    //  调用参数不给值,返回的的就是默认值 “5”
    test()
    
    
  • 可变参数

    • swift函数的参数个数可以变化,可以接收不确定数量的输入类型参数
    • 需要注意的是,这些参数必须具有相同的类型
    • 方法:在参数类型后面加 "..." 表示参数为可变参数


    //  定义函数,参数为可变参数
    func test(nums : Int...) -> Int {
    
        var sum : Int = 0
        //  遍历内部元素
        for temp in nums {
            sum += temp
        }
    
        return sum
    }
    
    //  调用函数,结果为202
    test(20, 15, 35, 32, 100)
    
    
  • 指针传递(引用类型)

    • 函数的参数是通过值传递的方式,如果想改变外面的变量,需要传递变量地址(默认)
    • swift提供了 "inout" 关键字来帮助我们实现
    • 需要注意的都是,操作的必须是变量,因为需要在内部改变值


    //  比如C语言中常见的问题:交换2个变量的值
    
    //  先来看看正常的值传递
    //  定义需要交换值的2个变量a,b
    var a = 6
    var b = 9
    
    //  值传递方式
    func test(var num1: Int, var num2: Int) -> (num1 : Int, num2 : Int) {
    
        let temp = num1
        num1 = num2
        num2 = temp
    
        return (num1,num2)
    }
    
    //  调用函数(交换的只是函数内部参数的值,而a,b的值并没变)
    test(a, num2: b)    //  结果 9  6
    print(a, b) //  结果  6   9
    
    //  通过上面的方式可以明显看出值传递并不能真实转换外部变量的值,在swift中我们可以通  过"inout"关键字来讲外部变量的值传给函数参数,再改变其值
    func test(inout num1 : Int, inout num2 : Int) -> (num1 : Int, num2 : Int) {
    
        let temp = num1
        num1 = num2
        num2 = temp
    
        return (num1, num2)
    
    }
    
    //  调用函数(因为传入的是a,b的变量地址,等于拿到了外部变量,函数内部操作的num1,num2可以看成a,b,因为他们的指针指向了a,b)
    test(&a, num2: &b)
    print(a,b)
    
    
  • 函数嵌套使用

    • swift中函数可以嵌套使用
    • 虽然可以嵌套使用,但是这种做法降低了可读性,所以尽量不要这样做

    //  函数嵌套
    
    let a = 100
    let b = 35
    
    func test() {
        func sum(num1 : Int, num2 : Int) {
            print("和为\(num1 + num2)")
        }
    
        print("test函数")
        sum(a, num2: b)
    }
    
    //  调用函数
    test()  //  先调用test函数,再调用sum函数
    
    

    注意:无法调用sum函数,因为它是test函数的一部分

  • 函数类型

    • 每个函数都有属于自己的类型,由函数的参数类型和返回值类型组成


    //  函数类型:定义2个函数,且都为 (String, String) -> (String) 类型
    
    func test1(name : String, city : String) -> String {
        return name + city
    }
    
    func test2(tiele : String, iconUrl : String) -> String {
        return "图片名称:\(tiele)图片地址为:\(iconUrl)"
    }
    
    
  • 将函数作当成变量传递

//  根据函数类型定义变量并将函数传递给变量
var tempFunction : (String, String) -> String = test1
//  使用变量名调用函数
tempFunction("sd", "lw")

  • 将函数当成参数使用
//  将函数当成参数使用
func test3(str1 : String, str2 : String, tempFunction : (String, String) -> String) {
    print(tempFunction(str1, str2))
}

//  调用函数
test3("aa", str2: "bb", tempFunction: test1)    //  结果 aabb

  • 函数当成返回值
//  函数作为方法返回值
/**
 *  判断一数是否为负数,是负数返回0,不是则返回原来的值
 */

//  正数调用此函数
func positive(num : Int) -> Int {
    
    return num
}
//  负数调用此函数
func negative(num : Int) -> Int {
    
    return 0
}

//  将函数作为返回值
func test(num : Int) -> (Int) -> Int {
    //  如果函数小于1就是负数,返回negative函数,如果大于1,则是正数,返回positive函数
    return num < 0 ? negative : positive
}

//  获取返回值(函数)
let function = test(-1) //  因为是负数,所以返回negative函数

//  调用方法(再将-1传入返回的函数)
function(-1)   //  结果为 0

枚举类型

  • 枚举用来定义一组通用类型的相关值,可以让达到让使用者按照设计者的规范使用特定的值

  • swift的枚举非常灵活,可以给枚举成员提供一个字符串,一个字符,一个整型或浮点值,不必给每个枚举成员提供值

  • C语言和OC里面枚举指定的一组相关成员为整型

  • 枚举类型定义

    • 使用 enum 关键词,将定义放在{}内
    • 使用 case 关键词定义新枚举成员
    • 需要注意的是,swift的枚举在被创建的时候不会像C和OC那样赋予默认整型值
    //  枚举定义
    enum testType {
        case testTypeOne
        case testTypeTwo
        case testTypeThree
    }
    //  当然也可以简写成下面的方式(在枚举成员特别多的情况下很好用)
    enum testType {
        case testTypeOne, testTypeTwo, testTypeThree
    }
    
    
  • 枚举类型赋值

  • 枚举类型赋值可以是整型、浮点型、字符、字符串

    • 如果有给枚举类型赋值,必须在枚举类型后面明确类型使用的类型


    //  枚举类型赋值
    enum testType1 : Int {
        case One = 1
        case Two = 2
        case Three = 3
    }
    //  或
    enum testType2 : Int{
        case One = 1, Two, Three
    }
    
    
  • 枚举类型使用

//  枚举类型赋值(整型)
enum testType1 : Int {
    case One = 1
    case Two 
    case Three 
}

//  枚举类型赋值(字符串)

enum testType2 : String{
    case One = "a", Two = "b", Three
}

let j = testType1(rawValue: 2)  //  获取到枚举成员Two

//  结果为Two
if let j = j {
    switch j {
    case .One:
        print("One")
    case .Two:
        print("Two")
    case .Three:
        print("Three")
    }
}

let i = testType2(rawValue: "a")    //  获取到枚举成员One

//  结果为One
if let i = i {
    switch i {
    case .One:
        print("One")
    case .Two:
        print("Two")
    case .Three:
        print("Three")
    }
}

注意:

1.如果明确了类型为整型且未设置初始值,那么由0开始依次递增(默认)

2.如果明确了类型为整型但设置了初始值,就由初始值依次递增


结构体(struct)

  • 结构体是一种数据结构

  • 结构体在方法(函数)中传递时时值传递,是值类型

  • 结构体是由一组相同类型或不同类型的数据组成的数据集合

  • 在特定情况下使用结构体,能使我们的代码结构更清晰

  • 定义结构体格式

struct 结构体名称 {
    属性
}

  • 结构体使用
/**
 *  在手势开发过程中,我们需要监听手指移动的位置,这边我们来判断手指移动的开始位置和结束位置距离是否大于50
 */
 
//  初始化结构体
struct touchPoint {
    var x : Double
    var y : Double
}

//  定义函数
func Range(point : touchPoint) -> Bool {
    let tempX = point.x - startX
    let tempY = point.y - startY
    //  sqrt(n)用来计算n的平方根
    //  pow(x, n)用来计算x的n次方
    let range = sqrt(pow(tempX, 2) + pow(tempY,2))
    
    return range > 50
}

//  创建结构体
let start = touchPoint(x:53.0, y:21.0)
let end = touchPoint(x: 120.0, y: 320.0)

//  调用函数
Range(point)    //  结果:true

  • 结构体增强
    • 扩充构造函数
      • 默认情况下创建touchPoint时使用touchPoint(x:,y:)
      • 为了更加灵活地使用结构体,swift支持对构造函数进行扩充
      • 在扩充的构造函数中必须保证成员变量有值
      • 扩充的构造函数会覆盖原有的构造函数

截止至:5.17 —— 1:00 5.18继续

类的定义

  • swift也是面向对象开发的语言,而面向对象的基础是类,由类产生对象

  • 在swift中定义类使用 class 关键字

  • 类的注意点:

    • 定义的类可以没有父类,也就是这个类就是rootClass
    • 一般情况下,定义类的时候,继承自NSObject(但并不是OC中的NSObject)
  • 格式:class 类名 : 父类 {
    属性,方法
    }

  • 类的属性

    • siwft中类的属性分为:
      • 存储属性: 存储实例常量和变量的属性
      • 类属性:与整个类自身相关的属性
      • 计算属性:通过某些算法计算出来的属性
  • 存储属性

    • 存储属性是最简单的属性,作为类实例的一部分,用于存储变量和常量
    • 可给存储属性提供默认值,也可以在初始化方法中对其进行初始化


    //  定义person类
    class person: NSObject {
        //  定义存储属性
        var name : String?  //  名字
        var age : Int = 0   //  年龄
    }
    
    //  创建person对象
    let ps = person()
    
    //  给存储属性赋值
    ps.name = "stephen"
    ps.age = 23
    
    
  • 类属性

    • 类属性是与类相关联的属性,但不是与类实例相关联的属性
    • 所有的实例和类共有一份类属性,所以只要有某一处修改,这个类的属性就会被修改
    • 类属性的设置和修改必须通过类来完成
    • 类属性使用 static 来修饰


    //  定义person类
    class person: NSObject {
        //  定义存储属性
        var name : String?  //  名字
        var age : Int = 0   //  年龄
    
        //  类属性
        static var nickName : String?
    }
    
    //  设置类属性值
    person.nickName = "laoWang"
    //  打印
    print(person.nickName!) //  结果:laoWang
    
    
  • 计算属性

    • 计算属性并不会存储实际的值,而是提供一个getter和一个setter(可选类型)间接获取和设置其它属性
    • 一般情况下,只会提供getter方法,这种情况下的计算属性为只读属性,可以省略 get{}


    //  定义person类
    class person: NSObject {
        //  定义存储属性
        var foodIntake : Double = 0.0 //    人的食量(一顿吃几碗)
        var consume : Double = 0.0   //     消耗量
    
        //  定义计算属性(差值)
        var difference : Double {
            get {
                return (foodIntake - consume)
            }
        
            //  newValue是系统自动分配的变量名,内部用来存储新的值
            //  里面放的是get方法里面计算的值
            set {
                self.difference = newValue
            }
        }
    
    }
    
    //  创建person对象
    let  ps = person()
    
    ps.foodIntake = 50  //  吃的有点多肯定比我胖
    ps.consume = 25 //  消耗这么多惊呆小伙伴,看来是个肌肉男
    
    //  打印
    print(ps.difference)    //  结果 25.0
    
    

类的属性改变监听

  • OC里面我们可以重写set方法来监听属性值的改变
  • swift则需要通过属性观察者来监听和相应属性值的变化
  • 一般只会监听存储属性和类属性改变,计算属性我们不需要定义属性观察者,因为我们可以在计算属性的setter中直接观察并响应其值得变化
  • swift使用下面的观察方法定义观察者
    • willSet:在属性值被存储之前设置(新值会通过常量参数的方式传入,这个参数就是newValue,我们可以给这个参数定义参数名,但一般保持默认)
    • didSet:新值被存储后立即调用这个方法,和willSet相同,这时传入的值是属性的旧值,默认的参数名叫oldValue
    • willSet和didSet只在属性第一次被设置的时候才会调用,初始化的时候并不会调用这2个监听方法
class person: NSObject {
    var name : String? {
        
        willSet (newValue) {    //  属性即将改变时调用
            //  会传入系统默认的属性newValue,用来存储新值
            print("name:\(name), newValue:\(newValue)") //  结果:name:nil, newValue:Optional("laoWang")
        }
        
        didSet (oldValue) {
            //  会传入系统默认的属性oldValue,用来存储旧值
            print("name:\(name), oldValue\(oldValue)")  //  结果:name:Optional("laoWang"), oldValuenil
        }
    }
    
}

//  创建person对象
let ps : person = person()

ps.name = "laoWang"


类的构造函数

  • 默认情况下创建一个类的时候,就会调用一个构造函数

  • 就算我们没有编写任何构造函数,编译器也会提供一个默认的构造函数

  • 如果类继承自NSObject,可以对父类的构造函数进行重写

  • 构造函数和OC中的初始化方法init:相似

  • 构造函数使用

    • 类的属性必须有值
    • 如果在定义时没有初始化值,可以在构造函数内进行赋值


    class person: NSObject {
    
        var name : String
    
        //  因为继承自NSObject,我们就重写(父类)的构造方法
        //  override关键字表示调用父类方法
        override init() {
            //  在初始化name属性时没有给它赋值,所以可以在构造函数里面进行赋值
            name = "laoWang"
        }
    }
    
    //  创建person对象
    let ps : person = person()
    
    print(ps.name)  //  结果:laoWang
    
    
  • 初始化时给属性赋值

    • 一般我们在创建一个对象的时候就会同时给属性赋值,这时候我们可以自定义构造函数
    • 需要注意的:如果我们自定义了构造函数,就会覆盖init:方法,也就是说不会有默认构造函数


    class person: NSObject {
    
        var name : String
    
        //  自定义构造函数,覆盖init:函数
        init(name : String) {
            //  在初始化self.name属性时没有给它赋值,所以可以在构造函数里面进行赋值
            self.name = name
        }
    
    }
    
    //  创建person对象
    let ps : person = person(name: "laoWang")
    
    print(ps.name)  //  结果:laoWang
    
    
  • 字典转模型方式一

    • 开发中,我们经常会将字典转换成模型在来使用,这边就以此做例子
    • 需要注意的是:字典中取出的数据类型为NSObject,我们可以通过as!将其转成需要的类型


    class person: NSObject {
    
        var name : String
    
        //  自定义构造函数,覆盖init:函数
        init(dict : [String : NSObject]) {
        
            self.name = dict["name"] as! String
        }
    
    }
    
    //  创建person对象
    let ps : person = person(dict:["name" : "laoWang"])
    
    print(ps.name)  //  结果:laoWang
    
    
  • 字典转模型方式二

    • 开发中我们经常会用KVC的方式将字典转成模型,这边就使用KVC对字典进行转换

    • 需要注意的是:KVC不能保证给所有属性赋值,所以属性需要有默认的值

      • 对象、结构体类型定义一般为可选类型就可以了,因为可选类型没有赋值前为nil
      • 基本数据类型一般设置为0


      class person: NSObject {
          //  KVC方式下,对象、结构体类型必须是可选类型,否则无法转换
          var name : String?
      
          //  自定义构造函数,覆盖init:函数
          init(dict : [String : NSObject]) {
      
              //  必须先初始化对象
              super.init()
      
              //  调用对象的KVC方法
              setValuesForKeysWithDictionary(dict)
           }
      
      }
      
      //  创建person对象
      let ps : person = person(dict:["name" : "laoWang"])
      
      print(ps.name)  //  结果:laoWang
      
      
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容