Swift:类与对象

Classes and Objects

github:Swift基础实例
github:SwiftBasicTableView

  1. 类的创建
    使用关键字 class ,后面跟上类名称,来创建一个类。
class Shape {
    var numberOfSides = 0
    let numberOfPoint = 3
    func simpleDescription() ->String {
        return "A shape with \(numberOfSides) sides"
    }
    func simplePoint(point:Int) ->Int {
        return point
    }
}

通过在类名后加圆括号() 来创建类的实例。用点语法(dot syntax),也就是对象加点调用 来访问实例中的属性和方法:

var shape = Shape()
shape.numberOfSides = 1
var shapeDes = shape.simpleDescription()
print(shapeDes)
  1. 构造器
    上面的类 Shape 少了一个重要的东西:当一个实例被创建的时候,用来构造这个类的初始化方法(可以称为构造器)。用 init 来生成一个这样的方法:
class NameShape {
    var numberOfSides: Int = 0
    var name :String
    init(name:String) {
        self.name = name
    }
    func simpleDescription() ->String {
        return "A shape with a name \(name)"
    }
}
var nameShape = NameShape(name: "ssss")
var initName = nameShape.simpleDescription()
  • 在创建类的实例的时候,它的一个属性name在初始化方法中被初始化
  • 每一个属性如果不是可选类型(加 ? 进行声明),都 必须 赋值---无论是 numberOfSides 还是初始化方法中的 name
  1. 析构器
    在对象释放时,可以在析构器中做些清理工作,用关键字 deinit 来生成一个析构器:
class NameShapeTwo {
    var numberOfSides: Int
    init(number:Int) {
        print("init called")
        self.numberOfSides = number
    }
    deinit {
        print("deinit called")
        numberOfSides = 0
    }
    func addNumbers(number:Int) {
        numberOfSides += 3
    }
}
var shapeTwo :NameShapeTwo? = NameShapeTwo(number: 3)
print("numberOfSides : \(shapeTwo!.numberOfSides)")
shapeTwo = nil
  • 输出顺序为:
    init called numberOfSides : 3 deinit called
  1. 类的继承
    子类包含父类的名字,用冒号 : 将子类名和父类名隔开。如果子类要重写/使用 父类已经定义过的方法,子类 必须 在该方法前加 override 关键字,如果不写 override 编译器会报错。而且编译器还会检测那些带有 override 的方法,判断这些方法是否是真的重写父类中的方法:
class Square: NameShape {
    var sideLength: Double
    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }
    
    func area() ->Double {
        return sideLength * sideLength
    }
    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}
var squareTest = Square(sideLength: 3.2, name: "subclass test")
squareTest.area()                 //10.24
squareTest.simpleDescription()    //"A square with sides of length 3.2."
squareTest.name                   //"subclass test"

同时需要注意:
1.子类可以设置自己声明的属性 2.子类可以改变在父类中定义的属性; 3.子类可以调用父类的方法,比如上面构造器方法 init;

  1. getter 和 setter
    除了存储属性,其它属性可以有一个 getter 和一个 setter 方法
class EquilateralTriangle: NameShape {
    var sideLength: Double = 0.0
    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }
    var perimeter: Double {
        get {
            return sideLength*3.0
        }
        set {
            sideLength = newValue / 3.0
        }
    }
    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)    //"9.3"
triangle.perimeter = 9.9
print(triangle.sideLength)   //"3.3"
  • perimetersetter 方法中,perimeter的新值有个默认名字 newValue,你也可以在 set 之后明确的指定一个名字,把名字放在()中,例如:set(perimeter) { sideLength = perimeter / 3.0}
  • 从上面的 getset方法和 OC 的方法有很大的区别,我们可以试着和 OC "相似"的方法来实现 sideLengthgetset方法:
class EquilateralTriangleOne: NameShape {
 
 init(sideLength: Double, name: String) {
     self.tempLength = sideLength
     super.init(name: name)
     numberOfSides = 3
 }
 
 var tempLength: Double = 0.0
 var sideLength: Double {
     get {
         print("getget")
         return self.tempLength
     }
     set {
         print("setset")
         self.tempLength = newValue
     }
 }
 override func simpleDescription() -> String {
     return "An equilateral triangle with sides of length \(self.sideLength)."
 }
}
var triangleOne = EquilateralTriangleOne(sideLength: 3.5, name: "b triangle")
print(triangleOne.sideLength) // getget 3.5
triangleOne.sideLength = 3.6  // setset
print(triangleOne.sideLength) // getget 3.6
  1. willSet 和 didSet
    如果你不需要计算一个属性,但是仍需要在这个属性被设置新值 之前之后,执行一些代码(暂且称为代码A),那么可以使用 willSetdidSet。在 构造器 之外,只要这个属性的值发生改变,代码A 都会被执行,类似观察者模式中的 property observe
class TriangleAndSquare {
    
    var triangleL: EquilateralTriangle {
        willSet {
            print("triangleL willSet")
            squareL.sideLength = newValue.sideLength
        }
       didSet {
            print("triangleL didSet")
        }
    }
    var squareL: Square {
        willSet {
            print("squareL willSet")
            triangleL.sideLength = newValue.sideLength
        }
        didSet {
            print("squareL didSet")
        }
    }
    init(size: Double, name:String) {
        // 少初始化任何一个对象,都会报错 
        // return from initializer without initializing all stored properties
        // 类似于 oc 的用来存储数据的 model,需要对象序列化一样
        squareL = Square(sideLength: size, name: name)
        triangleL = EquilateralTriangle(sideLength: size, name: name)
    }
}
var triangleAndSquare = TriangleAndSquare(size: 5.0, name: "another shape")
print(triangleAndSquare.squareL.sideLength)       // 5.0
print(triangleAndSquare.triangleL.sideLength)     // 5.0
triangleAndSquare.squareL = Square(sideLength: 10.0, name: "lager shape") //squareL willSet   squareL didSet
print(triangleAndSquare.triangleL.sideLength)     // 10.0
  • 注意上面的注释部分
  1. 操作符?
    用操作符? 来表示一个值是可选的,如果 ? 前面的值是 nil,那么 ? 后面的所有操作都会被忽视,然后这个表达式的值会变为 nil:
let optionalSquare : Square? = Square(sideLength:5.3, name: "optionalSquare")
var optionalLength = optionalSquare?.sideLength
  • 如果 optionalSquarenil,那么就不会调用sideLengthoptionalLength的值变为 nil
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,009评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,808评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,891评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,283评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,285评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,409评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,809评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,487评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,680评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,499评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,548评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,268评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,815评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,872评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,102评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,683评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,253评论 2 341

推荐阅读更多精彩内容