swift面向对象基础<二>

存储属性和计算属性

今天讨论实例存储属性与实例变量,结构体常量与实例属性,定义计算属性,setter方法,属性观察者

存储属性:存储在类和结构体里的变量和常量。分为实例存储属性和类型存储属性,实例存储属性是指单个的实例,用来保存实例的状态和数据。类型存储属性:属于类型本身。类,结构体,枚举都可以定义成类型存储属性。枚举不可以定义成实例存储属性,

所有的存储属性都必须显示的指定初始值,可以在定义时或者构造器中指定。
可选类型的存储属性是可以不指定初始值的
1.程序为所有的实例存储属性指定了初始值,且没有构造器。则系统会提供2个构造器:一个无参数的构造器和一个初始化所有实例存储属性的构造器
2.属性没有初始值也没有构造器,系统提供一个初始化所有属性的构造器
3.有构造器,则要早构造器中为所有的属性提供初始值
通过构造器函数完成对存储属性的初始化:

//存储属性
struct lengthrange{
    var start: Int
    //定义常量存储属性,可以不指定初始值
    let length: Int
}

var len = lengthrange(start: 9, length: 3)
print(len.start,len.length)
//定义一个结构体常量与她的实例属性
struct lengthrange2{
  var start: Int
  var length: Int
}
let len2 = lengthrange(start: 1, length: 2)//不可以改变实例属性

延迟存储属性:第一次调用的时候才会计算初始值的属性,用lazy的修饰符
延迟存储是一种延迟机制,只能声明成变量。

计算属性

计算属性就相当于oc中的getter和setter方法合成的属性,
计算属性的格式:

/*
 [修饰符]var 计算属性名:属性类型{
 get {
 //get方法执行体,该方法一定要有返回值
 }
 set(形参名){
 set方法执行体,该方法一定不能有返回值
 }
 
 */

属性观察者:用来观察属性的变化的,为了让属性在被赋值的时候获得执行代码的机会
1.它可以监听除了延迟属性之外的所有存储属性(包括类型存储属性和实例存储属性)
2.可以通过重载的方式为继承得到的属性添加属性观察者

/*
 属性观察者:
 [修饰符]var 计算属性名: 属性类型 = 初始值{
 will set(newvalue){
 //属性即将被赋值之前调用的方法
 }
 didset(oldvalue){
 //属性被赋值完成之后自动调用的方法
 }
 willset和didset后面的参数都是可以省略的
 
 */
class user{
    var first: String = ""
    var last: String = ""
    //定义计算属性
    var fullname: String{
        //定义计算属性的getter方法,该方法的返回值有first,last两个存储属性决定
        get{
            return first + "-" + last
        }
        //定义计算属性的setter方法
        //该setter方法将负责改变该实例的first,last两个存储属性
        set(newvalue){
            var names = newvalue.components(separatedBy: "-")
            self.first = names[0]
            self.last = names[1]
        }
    }
    init (first: String , last: String){
        self.first = first
        self.last = last
    }
    
}

let s = user(first: "swift", last: "hello")
print(s.fullname)//调用get方法
s.fullname = "hello-swift"//调用setter方法
print(s.first)

//只读属性,不需要set部分,可以省略get和花括号
//属性观察者

class person {
    //定义存储属性
    var name: String = "" {
        willSet{
            if newValue.characters.count>6 || newValue.characters.count < 2 {
                print("你设置的人名不符合要求,请重新设置")
            } else{
            print("人名设置成功")
            }
        }
        didSet{
            print("人名设置完成,被修改的原名:\(oldValue)")
        }
    }
    var age : Int = 0{
        willSet{
            if newValue > 100 || newValue < 0 {
                print("设置的年龄\(newValue)不符合要求")
            } else{
                print("年龄设置成功!")
            }
        }
        didSet{
            print("年龄设置完成,被修改的年龄为\(oldValue)")
        }
    }
}

var p = person()
p.age = 999

p.age = 10//将会调用willset和didset方法

swift面相对象中的方法

在方法中,谈论的是方法的所属性,方法转换为函数,方法的外部形参名,值类型的可变方法,属性和方法的统一

1.定义方法需要在枚举,结构体,类中定义,不能够独立的定义
2.方法可以使类型本身,也可以是属于实例
3.不能独立使用方法,需用类型或者实例充当调用者
4.枚举和结构体中的方法用static修饰,类中用class修饰,都属于类方法。否则属于实例方法
//将方法转换成函数

class someclass {
    func test() {
        print("==test 方法 ==")
    }
    class func bar(msg: String){
        print("== bar 类型方法==,传入的参数:\(msg)")
    }
}

//创建实例
var sc = someclass()
//将sc的test方法分离成函数
var f1 : ()->() = sc.test//不能有(),()标示调用方法,没有()标示赋值给f1,从而把方法转变成了函数

//将sc的bar方法分离成函数
var f2:(String) -> Void = someclass.bar

//直接调用函数就等于调用了方法
f1() //等价于sc.text()
f2("swift")

方法的外部形参名

//方法的外部形参名
class person {
    
    var name: String
    
    init(name: String){
        self.name = name
    }
    
    func eat (food: String , drink: String , cigarette: String){//在方法名的前面添加“_”标示不需要外部参数名
        print("\(self.name)吃着\(food),喝着\(drink),抽着\(cigarette)")
    }
}
var p = person(name: "tom")
p.eat(food: "烤鸭", drink: "啤酒", cigarette: "雪茄")//swift默认会添加外部参数名,

值类型的可变方法

值类型代表的是结构体或者是枚举,将mutating放在func之前,即将该方法声明为可变方法

struct jkrect {
    var x: Int
    var y: Int
    var width: Int
    var height: Int
    mutating func movebyx(x: Int, y: Int) {
        self.x += x
        self.y += y
    }
}

//创建实例
var rect = jkrect(x: 20, y: 12, width: 200, height: 300)
//调用mutating方法,该方法可以改变rect实例的存储属性
rect.movebyx(x: 100, y: 90)
print("rect举行的左上角的x坐标为:\(rect.x),y\(rect.y)")
//注意:常量类型的结构体,枚举是不可变的

属性和方法的统一

1.使用函数类型定义属性,并将函数或者闭包作为该属性的初始值,这个属性就成了方法。

//属性和方法的统一

func factorial(n: Int) -> Int{
    var result = 1
    for i in 1...n {
        result *= i
        
    }
    return result
}

struct somestruct {
    var info: () -> Void = {
        print("info方法")
    }
    //将全局函数作为fact存储属性的初始值
    static var fact: (Int) -> Int = factorial
}

var sc = somestruct()
//调用info方法
sc.info()

//使用闭包对sc对象发的info赋值,相当于重新定义sc的info方法
sc.info = {
    print("另外一个闭包")
}

sc.info()

var n = 6

//调用的fact方法,执行的是阶乘
print("\(n)的阶乘是:\(somestruct.fact(6))")
//使用闭包对somestruct的fact赋值,相当于重新定义somestruct的fact方法
somestruct.fact = {
    var result = 1
    for i in 1...$0{
        result += i
    }
    return result
}
//再次调用fact方法,执行的是累加
print("\(n)的累加的和")

下标
需要了解下标的用法和下标的重载

1.所有的swift类型(枚举,类,结构体)都支持下标
2.同一个类型可以定义多个下标值
3.通过下标的形参列表或者返回值的类型来区分不同的下标
4.同一个类型中定义多个不同的下标,被称为下标重载。

//下标的基本用法
/*
 Subscripe(形参列表) -> 下标返回值类型 {
 get {
 //get方法执行体,该方法一定有返回值
 }
 set (形参名){
 //setter方法执行体,该方法可以没有返回值
 }
 
 }
 形参列表:与函数的形参列表的用法基本相同,但是不支持指定外部参数和默认值
 下标返回值类型:可以是任何有效的类型
 */
//下标
struct jkrect2 {
    var x: Int
    var y: Int
    var width: Int
    var height: Int
    
    //定义下标,指定下标只接受int类型的参数,下标返回类型为int
    subscript (index: Int) -> Int{
        //get部分
        get{
            switch(index){
            case 0:
                return self.x
            case 1:
                return self.y
            case 2:
                return self.width
            case 3:
                return self.height
            default:
                print("不支持该索引值")
                return 0
            }
        }
        //set部分
        set{
            switch(index){
            case 0:
                self.x = newValue
            case 1:
                self.y = newValue
            case 2:
                self.width = newValue
            case 3:
                self.height = newValue
            default:
                print("不支持该索引值")
            }
        }
        
        
    }
}

//创建实例
var rect2 = jkrect2(x: 20, y: 12, width: 200, height: 300)
//通过下标进行赋值
rect2[0]=40
rect2[1] = 67
//通过下标访问rect中的函数
print("rect2矩形的x坐标\(rect2[0])y坐标为 \(rect2[1])")

//省略下标中的set部分即是只读下标

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

推荐阅读更多精彩内容