swift面向对象基础<三>

接下来就讨论一下可选链,类型属性和类型方法,构造器

1.可选链是用于处理可选类型的属性,方法和下标
2.使用可选链代替强制解析
3.调用方法
4.调用下标

//创建3个关联类
class customer{
    var name = ""
    var emp: employee?
    init(name: String){
        self.name = name
    }
}

class company {
    var name = ""
    var addr = ""
    init(name: String , addr: String){
        self.name = name
        self.addr = addr
    }
}

class employee{
    var name = ""
    var title = "行政"
    var company: company!
    init(name: String, title: String){
        self.name = name
        self.title = title
    }
    func info() {
        print("本员工名为\(self.name),职位为\(self.title)")
    }
}

var c = customer(name: "tom")
var emp = employee(name: "jack", title: "student")
//设置customer关联的employee实例
c.emp = emp
//设置empoyee关联的compony实例
emp.company = company(name: "swift", addr:"shanghai")
print("为\(c.name)服务的公司是:\(c.emp!.company.name)")

//第二种情况
var c2 = customer(name: "lucky")
//设置customer关联的employee实例
c2.emp = employee(name:"helly", title: "客服")
//print(c2.emp!.company.name)//此时是没有为company赋值的,它的值为nil.为此使用可选链访问属性
//使用可选链访问属性
/*
 可选链的访问方式:将强制解析的!换成?,即是是隐式解析后面也要添加?
 
 */
print(c2.emp?.company?.name)//输出为nil
//可选链会自动防伪关联属性的可选情况,自动判别是否为nil

通过可选链来访问方法和下标

首先做可选链访问方法

//创建3个关联类
class customer{
    var name = ""
    var emp: employee?
    init(name: String){
        self.name = name
    }
    
    //定义一个常量类型的employee数组,用于模拟系统中所有的员工
    let employees = [employee(name: "张三" , title: "销售"),
                     employee(name: "小明" , title: "售后"),
                     employee(name: "han" , title: "普通员工"),
                     employee(name: "better" , title: "销售主管")
                     ]
    //定义一个方法,该方法可根据员工名返回对应的员工,返回值为可选类型
    func findemp(empname: String) -> employee!{
        for emp in employees{
            if emp.name == empname {
                return emp
            }
        }
        return nil
    }
}

class company {
    var name = ""
    var addr = ""
    init(name: String , addr: String){
        self.name = name
        self.addr = addr
    }
}

class employee{
    var name = ""
    var title = "行政"
    var company: company!
    init(name: String, title: String){
        self.name = name
        self.title = title
    }
    func info() {
        print("本员工名为\(self.name),职位为\(self.title)")
    }
}
//通过可选链来调用方法
var c3 = customer(name: "paul")
c3.findemp(empname: "张三")?.info()
c3.findemp(empname: "小明")?.info()

可选链访问下标

//可选链访问下标
var dict = [Int : customer]()
dict[1] = customer(name: "han")
dict[2] = customer(name: "angle")

dict[1]?.findemp(empname: "better")?.info()
dict[4]?.findemp(empname: "better")?.info()

类型属性和类型方法

值类型的类型属性

//1.值类型的类型属性
enum season {
    //为枚举定义类型存储属性,使用可选类型,系统将其初始化为nil
    static var desc : String?
    //为枚举定义类型存储属性,且声明为常量
    static let name = "季节"
    static var info: String{
        get{
            return "代表季节的枚举,其desc为:\(desc)"
        }
        set{
            print("程序尝试对info计算属性进行赋值:\(newValue)")
        }
        
    }
}
//对season枚举的类型属性赋值
season.desc = "季节类"
print(season.name)
season.info = "新的info"
print(season.info)
//结构体可以包含实例计算属性,不能包含实例存储属性

struct fkrange{
    //为结构体定义类型存储属性,使用可选类型,系统将其初始化为nil
    static var desc : String?
    //为结构体定义类型存储属性,且声明为常量
    static let maxwidth = 10000
    static let maxheight = 40000
    //定义类型计算属性,该属性只有get部分,是一个只读属性
    static var maxarea: Int{
        return maxwidth * maxheight
    }
    
}
fkrange.desc = "描述范围的结构体"
print(fkrange.desc)
print(fkrange.maxwidth)
print(fkrange.maxheight)
print(fkrange.maxarea)

class在类中修饰属性和方法

类的属性:

//类的类型属性
class user{
    //为类定义类型计算属性
    class var namemaxlength: Int {
        get{
            return 24
        }
        set{
            print(newValue)
        }
    }
}
print(user.namemaxlength)
user.namemaxlength = 20
//类中不可以定义类型存储属性,只能包含类型存储属性

值类型的类型方法

//值类型的类型方法
enum season2{
    //为枚举定义类型存储属性,使用可选类型,系统将其初始化为nil
    static var desc : String?
    //为枚举定义类型存储属性,且声明为常量
    static let name = "季节"
    //定义无参数的类型方法
    static func info(){
        print("季节类的info方法")
    }
    //定义一个带参数的类型方法
    static func setdesc(desc : String){
        self.desc = desc
    }
}
season2.info()
season2.setdesc(desc: "季节变化的枚举")
print(season2.desc)

类的类型方法:

//类的类型方法
class math{
    //类中不允许定义类型存储属性,使用类型计算属性代替
    class var pi: Double{
        return 3.1415
    }
    class func abs(value: Double) -> Double{
        return value < 0 ? -value : value
    }
    //定义类型方法,取消第二个形参的外部形参名
    class func pow(base: Double, _ exponet: Int) -> Double{
        var result = 1.0
        for idx in 1...exponet{
            result *= base
        }
        return result
    }
    //定义类型方法,类型方法可以直接访问类型属性
    class func radian2degree(radian: Double) -> Double{
        return radian*180 / pi
    }
    //定义类型方法,类型方法可通过self应用类型属性
    class func degree2radian(degree: Double) -> Double{
        return degree * self.pi / 180
    }
    
}
print(math.pi)
print(math.pow(base: 2, 5))
print(math.radian2degree(radian: 1.3))
print(math.degree2radian(degree: 1.2))

构造器

1.swift构造器构造出来的实例有系统隐式返回
2.构造器的作用完成结构体和类实例存储属性的初始化
3.为实例存储属性赋初值的时机:
1>定义实例存储属性时赋初始值
2>在构造器中为实例存储属性赋初始值

实例存储属性的初始化分类:
1>定义实例存储属性时,显示指定了初始值
2>实例存储属性的类型为可选类型
3>系统提供的默认构造器为实例存储属性提供初始值
4>显示提供的构造器为实例存储属性提供初始值

类和结构体的构造器

swift只为类提供一个无参数的构造器
swift为结构体提供2个构造器:无参数的构造器和初始化所有实例存储属性的构造器

可能失败的构造器

结构体,枚举或者是类不能成功返回这个类型的实例。如:用户传入的参数不对,会让构造器的创建失败,而此时就需要可能失败的构造器

1.使用init?或者init!来进行定义
2.在构造器执行体中return nil 标示构造器失败
3.swift不允许构造2个形参列表的构造器,即是一个是可能失败的构造器,一个是普通的构造器也不行。

构造器的外部形参名

//构造器的外部形参名
struct fkpoint{
    var left: Int = 0
    var top: Int = 0
    //定义带两个参数的构造器,并为第二个参数显示指定外部形参名
    init(left: Int , y top: Int){
        self.left = left
        self.top = top
    }
    
}

var p1 = fkpoint(left: 20, y: 12)

取消构造器的外部形参名

//取消构造器的外部形参名
class person {
    var name: String?
    var gender: String?
    var age = 0
    //由于该类中前2个实例存储属性使用了可选类型,后一个存储属性指定了初始值
    //因此该结构体对构造器没有要求,故此处可以随便定义构造器
    //取消构造器参数的外部形参名
    init(_ name: String, _ gender: String){
        self.name = name
        self.gender = gender
    }
}
//调用构造器时无需要使用外部形参名

var p = person("虽无空", "南")
print(p.name)

在构造过程中,使用闭包初始化存储属性

//使用闭包或函数为属性设置初始值
struct closureinit {
    //使用闭包对test实例属性执行初始化
    var test: Int = {
        var dt = NSDate()
        var gregorian = NSCalendar.current
        //定义一个时间字段的旗标,指定将会获取指定月日的信息
        var unitflags = NSCalendar.Unit.month | NSCalendar.Unit.day
        var comp = gregorian.component(unitflags, from: dt)
        //获取当前的月份
        var month = Int(comp.month)
        return month
    }()
}

值类型的构造器重载

//值类型的构造器重载
struct constructoroverload {
    var name: String?
    var amount: Int?
    //提供无参数的构造器
    init(){}
    //提供带两个参数的构造器来完成构造过程
    init(name: String, amount: Int){
        self.name = name
        self.amount = amount
    }
}
//通过无参数构造器创建constructoroverload实例
var oc1 = constructoroverload()
//通过有参数构造器创建constructoroverload
var oc2 = constructoroverload(name: "swift", amount: 8000)
print(oc1.name)
print(oc2.name)

构造器代理

在定义构造器时,通过self,init(实参)来调用其它构造器,来完成实例的部分构造过程

//构造器代理
struct apple{
    
    var name: String
    var color: String
    var weight: Double!
    
    init(_ name: String , _ color: String)
    {
        self.name = name
        self.color = color
    }
    
    //两个参数的构造器
    init(name: String, color: String){
        self.init( name, color)
    }
    
    //为构造器显示指定外部形参名
    init(applename n: String, applecolor c: String){
        self.init(n, c)
        
    }
}

//可能失败的构造器

//可能失败的构造器
struct cat {
    let name: String
    init?(name: String){
        //如果传入的name参数为空字符串,构造器失败,返回nil
        if name.isEmpty {
            return nil
        }
        self.name = name
    }
    
}

enum season {
    case spring, summer, autumn, winter
    //使用init!定义可能失败的构造器,则改构造器创建的实例可以进行隐式解析
    init!(name: Character){
        switch name {
            case "s":
            self = .spring
            case "u":
            self = .summer
            case "a":
            self = .summer
            case "w":
            self = .winter
        default:
            return nil
        }
        
    }
}

你可能感兴趣的:(swift面向对象基础<三>)