Swift--属性与下标

  • 存储属性
  • 计算属性
  • 属性观察者
  • 静态属性
  • 使用下标

存储属性

存储属性概念

存储属性可以存储数据,分为常量属性(用关键字let定义)和变量属性(用关键字var定义)。存储属性适用于类和结构体两种Swift面向对象类型。

注意:存储属性适用于类和结构体,不适用于枚举类型。

这些属性要么在构造函数中去赋予初始值,要么在定义的时候去赋予初始值,如下图:
struct Department {
    var no: Int = 0
    var name: String = "SALES"
    init() {
        self.no = 0
        self.name = ""
    }
}
看看下面的代码
class Employee {
    var no: Int = 0
    var name: String = "Tony"
    var job: String?
    var salary: Double = 0
    var dept: Department? = Department()
}

struct Department {
    var no: Int = 0
    var name: String = "SALES"
}

let emp = Employee()
emp.no = 100
emp.name = "top"

let dept = Department()
dept.name = "SALES"   //编译错误

如下图:Department被声明为let会报错


屏幕快照 2019-10-09 上午12.51.42.png

原因解释:
Employee是类这种类型,即引用数据类型,引用数据类型实际上是一种指针类型,对指针声明为let没有关系,这就是所谓的像C++语言中的指针常量类型,这种常量类型可以保证指针本身不被修改,但是指针所指的内容可以被修改
Department是一个结构体,结构体是值类型,值类型被声明成let后就不能被修改

注意:引用类型相当于指针,emp相当于常量指针,常量指针是不可能修改的,但是它所指向的内容可以修改。而常量值类型dept, 无论是结构体还是枚举类型都不能被修改。

延迟存储属性

或许我们不关心员工隶属于哪个部门,只关心他的no(编号)和name(姓名)。虽然不使用dept实例,但仍然会占用内存。Swift采用了延迟加载技术。

//延迟存储属性

class Employee2 {
    var no: Int = 0
    var name: String = "Tony"
    var job: String?
    var salary: Double = 0
    lazy var dept: Department2 = Department2()
}

struct Department2 {
    var no: Int = 0
    var name: String = ""
}

let emp2 = Employee2()
emp2.no = 100
emp2.name = "Martin"
emp2.job = "Sale"
emp2.salary = 5000

print(emp2.dept.no)

emp2

Employee2中的dept使用了延迟加载后,在 print(emp2.dept.no)这段代码前,emp2中的dept值为nil

image.png

在 print(emp2.dept.no)这段代码后,emp2中的dept有具体的值

image.png

计算属性

计算属性概念

计算属性本身不存储数据,而是从其他存储属性中计算得到数据。与存储属性不同,类、结构体和枚举都可以定义计算属性

计算属性语法格式
面向对象类型 类型名  {
      存储属性
      ...
      var  计算属性名 : 属性数据类型  {
              get  {
                      return  计算属性值
              }
              set ( 新属性值)  {
                      ...
              }
      }
}

class Employee3 {
    var no: Int = 0
    var firstName: String = "张"
    var lastName: String = "三"
    var job: String?
    var salary: Double = 0
    lazy var dept: Department3 = Department3()

    var fullName: String {
        get {
            return firstName + "." + lastName
        }
    
        set {
            //newValue是由系统提供的名字,也就是传进来的值,即        emp3.fullName = "李.四"中的李四
            //newValue 本质是String--> NSString  (桥接)
            var name = newValue.components(separatedBy: ".")
            firstName = name[0]
            lastName = name[1]
        }       
    }
}

struct Department3 {
    var no: Int = 0
    var name: String = ""
}

let emp3 = Employee3()
print(emp3.fullName)

emp3.fullName = "李.四"
print(emp3.fullName)

: newValue是由系统提供的名字,也就是传进来的值,即 emp3.fullName = "李.四"中的李四

也可以不用系统的newValue,自定义一个参数名为newFullName

如下面的代码,把上面的set部分改为下面的样式
 //也可以不用系统的newValue,自定义一个参数名为newFullName
        set (newFullName) {
            var name = newFullName.components(separatedBy: ".")
            firstName = name[0]
            lastName = name[1]
        }
计算属性的只读属性

未省略时

var fullName: String {
   get {
        return firstName + "." + lastName
    }
}

省略时

var fullName: String {
    return firstName + "." + lastName
}
结构体中的计算属性

结构体中定义属性和类中没有本质的区别

struct Department3 {
    var no: Int = 0
    var name: String = ""
    var fullName: String {
        return "研发部." + "业务支持中心"
    }
}
print(emp3.dept3.fullName)
枚举中的计算属性(和类中一样)

//枚举中的计算属性
enum WeekDays : String {
    case Monday    = "Mon."
    case Tuesday   = "Tue."
    case Wednesday = "Wed."
    case Thursday  = "Thu."
    case Friday    = "Fri."

    // 只读计算属性 
    var message : String {
        return "Today is " + self.rawValue
  }
}

var day = WeekDays.Monday
print(day.message)

属性观察者

Swift中的属性观察者主要有以下两个
  • willSet: 观察者在修改之前调用。
  • didSet: 观察者在修改之后立刻调用。

注意: 属性观察者不能监听延迟存储属性和常量存储属性的变化。

属性观察者的语法格式
面向对象类型 类型名  {
      ...
      var  存储属性: 属性数据类型 = 初始化值  {
              willSet (新值)  {
                     ...
              }
              didSet ( 旧值)  {
                      ...
              }
      }
}

不指定新值和旧值,系统会自动分配一个newValue 或oldValue

//属性观察者

class Employee4 {
    var no: Int = 0
    var name: String = "Lucy" {
        willSet (newNameValue) {
            print("员工name新值:\(newNameValue)")
        }
        didSet(oldNNameValue) {
            print("员工name旧值:\(oldNNameValue)")
        }
    }
    var job: String?
    var salary: Double = 0
    var dept: Department4?
}

struct Department4 {
      var no: Int = 10 {
         willSet {
              print("部门编号新值:\(newValue)")
          }
          didSet {
              print("部门编号旧值:\(oldValue)")
          }
      }
      var name: String = "销售部门"
  }

let emp4 = Employee4()
emp4.no = 100
emp4.name = "Lily"

var dept = Department4()
dept.no = 30

输出结果如下:


image.png

静态属性

实例属性隶属于某一个实例,而静态属性隶属于具体的类型,属于这个类型下面的所有的实例。

静态属性的概念

有一个Account(银行账户)类,假设它有3个属性:amount(账户金额)、interestRate(利率)和owner(账户名)。在这3个属性中,amount和owner会因人而异,不同的账户这些内容是不同的,而所有账户的interestRate都是相同的。
amount和owner属性与账户个体有关,称为实例属性。interestRate属性与个体无关,或者说是所有账户个体共享的,这种属性称为静态属性类型属性

结构体静态属性语法格式
struct 结构体名  {
      static var(或let) 存储属性 = "xxx"
      ...
      static var  计算属性名 : 属性数据类型  {
              get  {
                      return  计算后属性值
              }
              set ( 新属性值)  {
                      ...
              }
      }
}
枚举静态属性语法格式
enum  枚举名  {
      static var(或let) 存储属性 = "xxx"
      ...
      static var  计算属性名 : 属性数据类型  {
              get  {
                      return  计算后属性值
              }
              set ( 新属性值)  {
                      ...
              }
      }
}
类静态属性语法格式
class  类名  {
      static var(或let) 存储属性 = "xxx"
      ...
      class(或static) var  计算属性名 : 属性数据类型  {
              get  {
                      return  计算后属性值
              }
              set ( 新属性值)  {
                      ...
              }
      }
}
类静态属性

类中不仅可以定义实例存储属性,还可以定义静态存储属性,声明静态存储属性的关键字是static。
类中也可以定义静态计算属性,声明使用的关键字是classstatic。类静态计算属性如果使用static定义,则该属性不能在子类中被重写(override); 如果使用class定义,则该属性可以被子类重写

结构体静态属性代码

//结构体静态属性
struct Account {
    var amount: Double = 0.0 //账户金额
    var owner: String = ""   //账户名

    static var interestRate: Double = 0.0668 //利率 静态存储属性
    static var staticProp: Double {
        return interestRate * 1_000_000  //静态计算属性
    }

    var instanceProp: Double {
        return Account.interestRate * amount //计算属性
    }
}

print(Account.staticProp)

var myAccount = Account()
//访问实例属性
myAccount.amount = 1_000_000

//访问静态属性
print(myAccount.instanceProp)

枚举静态属性代码

//枚举静态属性(不可以定义实例存储属性)
enum Account2 {
    case 中国银行
    case 中国工商银行
    case 中国建设银行
    case 中国农业银行

    static var interestRate: Double = 0.0668 //利率 静态存储属性

    static var staticProp: Double {
        return interestRate * 1_000_000  //静态计算属性
    }

    var instanceProp: Double {
        switch (self) {
            case .中国银行:
                Account2.interestRate = 0.667
            case .中国工商银行:
                Account2.interestRate = 0.669
            case .中国建设银行:
                Account2.interestRate = 0.666
            case .中国农业银行:
                Account2.interestRate = 0.668
       }
       return Account2.interestRate * 1_000_000
    }
}

//访问静态属性
print(Account2.staticProp)

var myAccount2 = Account2.中国银行

//访问静态属性
print(myAccount2.instanceProp)

枚举不可以定义实例存储属性,可以定义静态存储属性

类的静态属性代码

//类的静态属性

class Account3 {
    var amount: Double = 0.0 //账户金额
    var owner: String = "" //账户名

    static let interestRate : Double = 0.0668 //利率 静态存储属性

    class var staticProp: Double {
        return interestRate * 1_000_000
    }

    var interestRate: Double {
        return Account3.interestRate * self.amount
    }
}

//子类覆盖父类的计算属性
class A: Account3 {
    override class var staticProp: Double {
        return interestRate * 1_000_000
    }
}
class B: A {
    override class var staticProp: Double {
        return interestRate * 1_000_000
    }
}

print(Account3.staticProp)

var myAccount3 = Account()
//访问实例属性
myAccount3.amount = 1_000_000

//访问静态属性
print(myAccount3.instanceProp)

注意: 下面的这个部分的静态存储属性 只能用static声明。

static let interestRate : Double = 0.0668 //利率

注意: 下面的这个部分的静态计算属性,如果没有子类需要重写当前类可以使用static和class声明,如果有子类需要重写当前类必须使用class声明

  class var staticProp: Double {
        return interestRate * 1_000_000
    }
归纳面向对象类型属性 如下图:
image.png

注意:
1、在静态计算属性中不能访问实例属性(包括存储属性和计算属性), 但可以访问其他静态属性
如下图:在静态计算属性staticProp中不能访问实例属性amount(存储属性)和owner(存储属性),也不能访问实例属性instanceProp(计算属性)

image.png

2、在实例计算属性中能访问实例属性,也能访问静态属性。
如下图:在实例计算属性instanceProp中 既可以访问实例属性amount,也可以访问静态属性interestRate。

image.png

使用下标

在Swift语言中只有一维数组,没有二维数组如果需要用到二维数组,就可以用下标

数组和字典中使用下标
//下标
var studentList: [String] = ["张三", "李四", "王五"]
studentList[0] = "诸葛亮"

var studentDictionary = ["102": "张三", "105": "李四", "109": "王五"]
studentDictionary["110"] = "董六"
下标访问语法格式
面向对象类型  类型名  {
      其他属性
       ...
      subscript(参数:参数数据类型) ->返回值数据类型 {
              get  {
                      return  返回值
              }
              set ( 新属性值)  {
                      ...
              }
      }
}

struct DoubleDimensionalArray {
    let rows: Int, columns: Int
    var grid: [Int]

    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        grid = Array(repeating: 0, count: rows * columns)
    }

    subscript(row: Int, col : Int) -> Int {
        get {
            return grid[(row * columns) + col]
        }
    
        set (newValue) {
            grid[(row * columns) + col] = newValue
        }
    }
}

let COL_NUM = 10
let ROW_NUM = 10

var array2 = DoubleDimensionalArray(rows: ROW_NUM, columns: COL_NUM)

for i in 0 ..< ROW_NUM {
    for j in 0 ..< COL_NUM {
        array2[i, j] = i * j
    }
}

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

推荐阅读更多精彩内容