自定义数据类型 — 类的属性和方法(swift)

下面简单的介绍结构体这一自定义数据类型的应用

  1. 计算属性
  2. 类型属性
  3. 类型方法
  4. 属性观测器
  5. 延迟属性
  6. 访问控制
  7. 单例模式初探

一:计算属性
struct Point {

    var x = 0.0

    var y = 0.0

}

struct Size {

    var height = 0.0

    var width = 0.0

}

class Rectangle {

    var origin = Point()//这个就好像origin是结构体的一个变量名,但是结构体又是类的属性

    var size = Size()

    var ddd = String()


    var ss :Size//注意:如果要将类中的属性,以结构体为例,那么有两种写法,第一种写法是属性后面加上:type。第二种写法是属性后面加上=type()
    //计算型的属性必须声明为var,因为它是一个变量,这里应该注意计算下属性的结构
    var center: Point{

        get{//这里表面取center的时候调用

            let centerX = origin.x + size.width / 2

            let centerY = origin.y + size.height / 2

            return Point(x: centerX, y: centerY)//这里返回的是一个点,返回的是Point结构体的初始化一样

        }

        set{//这里表明给center赋值的时候调用,newCenter是传递进来的值,当然也可以使用系统默认的newValue

            origin.x += newValue.x - center.x

            origin.y += newValue.y - center.y

        }

    }

    var area: Double{//这里记住get必须要有一个返回值,就像center属性一样,放回的是Point类型,这里放回的是double类型

        get{

        return size.height * size.width


        }


    }

//      这句话报错的原因是:如果一个计算属性有set方法,就必须要有get方法,而且计算属性一定要指明数据类型
//    var sss: Double{
//    
//        set{
//        
//        
//        
//        
//        }
//        
//    
//    }



    init(origin: Point , size: Size ,ss: Size){

        self.origin = origin

        self.size = size

        self.ss = ss
    }


}

//这个有点像frame的设计思想,这句话的意思是:通过init构造函数初始化类,
var rect = Rectangle(origin: Point(x: 0, y: 0), size: Size(height: 20, width: 19), ss: Size(height: 20, width: 20))

rect.origin = Point(x: 10, y: 10)

rect.center

rect.center = Point()//将中心点的位置设置为0,0

rect.center

rect.area
二:类型属性
Int.max//这就是类型的属性,将类型方法或者属性定义在类型上

Int.min

class Player {

    var name: String

    var score = 0

    //现在我有个需求,就是想有一个最大的分值,这样我就需要将这个最大的分值属性定义在类型上,使用static关键字修饰,使得hightestScore这个属性不会因为再次调用类的时候初始化

    static var hightestScore = 0


    init(name: String){


        self.name = name

    }

    func play() {


        let score = random()%100 //注意:score是局部变量

        print("\(name) play the game and get \(score) score")

        self.score += score

        print("the total score of \(name) is \(self.score) score")

        if self.score > Player.hightestScore{

        Player.hightestScore = self.score


        }
        //这样就在这个类上定义了一个最高分
        print("the hightest score is \(Player.hightestScore)")


    }


}

var play = Player(name: "yhy")

var play2 = Player(name: "yhy1")


play.play()
play.play()
play.play()
play2.play()
play2.play()
play2.play()
三:类型方法
struct Matrix{

    var m: [[Int]]
    var row: Int
    var col: Int

    init?( _ arr2d:[[Int]] ){

        guard arr2d.count > 0 else{
            return nil
        }

        let row = arr2d.count
        let col = arr2d[0].count
        for i in 1..<row{
            if arr2d[i].count != row{
                return nil
            }
        }

        self.m = arr2d
        self.row = row
        self.col = col
    }

    static func identityMatrix(n: Int) -> Matrix?{

        if n <= 0{
            return nil
        }

        var arr2d:[[Int]] = []
        for i in 0..<n{
            var row = [Int](count: n, repeatedValue: 0)
            row[i] = 1
            arr2d.append( row )
        }

        return Matrix(arr2d)
    }

    func printMatrix(){
        for i in 0..<row{
            for j in 0..<col{
                print(m[i][j],terminator:"\t")
            }
            print()
        }
    }
}


let m = Matrix([[1,2],[3,4]])!
m.printMatrix()

let e = Matrix.identityMatrix(6)!
e.printMatrix()
四:属性观测器
//property observer
//属性观察器就是willSet和didSet,但是,需要特别强调的是,虽然当属性的值发生变化的时候,就会执行willSet和didSet大括号里面的语句,但是如果是构造方法的赋值,就不会执行willSet和didSet大括号里面的语句,这点要注意
class LightBulb {

    static  let maxCurrent = 30

    var current = 0{

        //观察属性和计算属性一样,如果你不想给以前的值或者新值取名字的话,可以使用newValue和oldValue
        willSet{//willSet会将要赋值的时候执行,那么将要赋值的时候,我们可以做一些操作

            print("the change is \(abs(current - newValue))")



        }


        didSet{//didSet表示已经将current进行了赋值,在didSet后面写上(oldCurrent)表示还没有赋值以前的值,大括号里,可以拿到已经进行赋值的值,也可以拿到赋值之前的oldCurrent的值

            if current == LightBulb.maxCurrent {

                print("that is the max")

            }else if current > LightBulb.maxCurrent {

            print("that is over the max")

                current = oldValue

            }

            print(current)

        }


    }





}


let  bulb = LightBulb()

bulb.current = 20

bulb.current = 30

bulb.current = 40

bulb.current = 59
五:延迟属性
//lazy property(懒加载属性)

class ClosedRange{

    let start: Int

    let end: Int

    var width: Int {

        get{

        return end - start + 1 //注意在swift的语法中呢,变量和运算符一定要隔开一个空格

        }

    }

    //现在我有个需求,想计算出start到end之间所有数的和,并且用到它的时候再调用,那么我将这个属性设置为懒加载属性
    //这个懒加载属性用“=”号连接一个闭包的函数,所以在{}后面还有加上(),那么我们在这里用到这个属性的时候就会调用这个属性的{}里面的内容,而且调用了之后,这个属性的值就会存储起来,下次调用的时候,就不会再次执行{}里面的内容了
    lazy var sum :Int = {

     print("sum")

    var tmp = 0

    for i in self.start...self.end{

    tmp += i

    }

    return tmp

    }()


    init?(start: Int, end: Int){//可能构造函数返回的是一个控制,所以使用可选型

        if start > end {

            return nil
        }

        self.start = start

        self.end = end

    }

}

if let closedRange = ClosedRange(start: 0, end: 10_000){

closedRange.width

closedRange.sum

closedRange.sum

closedRange.sum

}
六:访问控制
/*访问控制
 *
 *1.public:可以被模块外访问
 *
 *2.internal:可以被本模块访问
 *
 *3.private:可以被本文件访问
 *
 */
七:单例模式初探
/*单例设计模式初探(由于需要用到两个文件,这里就不上代码了!!!)
 *在这个例子中,一个类被外界访问之后,当拿到这个类的时候,就会重新调用这个类的初始化方法,那么这个类中的原有属性将再初始化,为了避免这个现象,我们可以将这个类中的初始化函数设置为private,现在当外界调用这个类的时候,就不能够初始化就会报错,好吧,那么作为一个类他会这么想,如果别人不能够初始化我,我就自己初始化自己吧,那么我们就可以在这个类里面定义一个变量,用这个变量来调用这个类,并且在属性前面加上一个static关键字,和public关键字,这样一来呢,这个变量就变成了一个类型属性,在外面,我们就可以直接用这个类拿到这个类型属性,就相当于初始化了这个类,问题解决了,好开心!!!
 */