在原有类型后面添加?,需要强制解析
在原有类型后面添加!,不需要强制解析
Swift的所有类型默认不能接受nil值,但是定义成可选类型就可以了,可选链就是用来处理可选类型的属性的,下标和方法,可以代替强制解析
可选链用于处理可选类型的属性.方法和下标
使用可选链代替强制解析
调用方法
调用下标
class Customer {
var name = ""
var emp: Employee?
init(name: String){
self.name = name
}
// 定义一个常量类型的employee数组,用于模拟系统中所有员工
let employees = [
Employee(name: "张三", title: "销售客服"),
Employee(name: "小明", title: "售后客服"),
Employee(name: "Devin", title: "普通客服"),
Employee(name: "Lucy", 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 = "Devin"
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: "Damon")
var emp = Employee(name: "Elena", title: "Student")
// 设置Customer关联的Employee实例
c.emp = emp
// 设置Employee关联的Company实例
emp.company = Company(name: "苹果", addr: "加利福利亚")
print("为\(c.name)服务的公司是:\(c.emp!.company.name)")
// 第二种情况
var c2 = Customer(name: "Lucy")
// 设置Customer关联的Employee实例
c2.emp = Employee(name: "Snow", title: "客服")
print("为\(c2.name)服务的公司是:\(c2.emp?.company?.name)")
// 使用可选链访问属性
var c3 = Customer(name: "Paul")
print("为\(c3.name)服务的公司是:\(c3.emp?.company?.name)")
1.可选链访问方式:将强制解析的感叹号换成?,在隐式解析的后面也添加?后缀
2.可选链会自动判断程序访问的关联实例是否为nil
c3.findEmp("张三")?.info()
c3.findEmp("小明")?.info()
var dict = [Int: Customer]()
dict[1] = Customer(name: "Devin")
dict[2] = Customer(name: "Angel")
//dict[1]?.findEmp("Lucy")?.info()
dict[4]?.findEmp("Lucy")?.info() // 4这个下标没有值
1.Swift的类型中可以定义5中成员:属性.方法.下标.构造器和嵌套类型
2.类型属性.实例属性
3.类型方法.实例方法
4.static:在枚举.结构体中修饰的属性.方法
5.class:在类中修饰的属性.方法
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 User {
// 为类定义类型计算属性
class var nameMaxLength: Int {
get{
return 24
}
set{
print("程序尝试对User类的nameMaxLength类型计算属性赋值\(newValue)")
}
}
}
print(User.nameMaxLength)
User.nameMaxLength = 20
// 类中不可以定义类型存储属性, 只能包含类型计算属性
enum Season2{
// 为枚举定义类型存储属性, 使用可选类型, 系统将其初始化为nil
static var desc: String?
// 为枚举定义类型存储属性, 且声明为常量
static let name = "季节"
// 定义无参数的类型方法
static func info(){
print("季节类的info方法, 该类的name存储属性为:\(name)")
}
// 定义带一个参数的类型方法
static func setDesc(desc: String){
self.desc = desc
}
}
Season2.info()
Season2.setDesc("描述季节变化的枚举")
print(Season2.desc)
class Math{
// 类不允许定义类型存储属性, 使用类型计算属性代替
class var pi: Double {
return 3.141592653589
}
class func abs(value: Double) -> Double {
return value < 0 ? -value: value
}
// 定义类型方法, 取消第二个形参的外部形参名
class func pow(base: Double, _ exponent: Int) -> Double {
var result = 1.0
for _ in 1...exponent{
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(2, 4))
print(Math.radian2Degree(1.57))
print(Math.degree2Radian(45))
1.Swift的构造器构造出来的实例由系统隐式返回
2.构造器的作用完成每个类, 结构体中实例存储属性的初始化
3.为实例存储属性赋初始值的时机:
1>定义实例存储属性时指定初始值
2>在构造器中为实例存储属性指定初始值
实例存储属性的初始化分类
1.定义实例存储属性时显示指定了初始值
2.实例存储属性的类型为可选类型
3.系统提供的默认构造器为实例存储属性分配初始值
4.显式提供的构造器为实例存储属性分配初始值
类和结构体的构造器
1.Swift只为类提供一个无参数的构造器
2.Swift为结构体提供两个构造器:无参数的构造器和初始化所有实例存储属性的构造器
可能失败的构造器
1.可能失败的构造器: 使用init? 或者init! 关键字进行定义
2.在构造器执行体中使用return nil来表示构造器失败
3.Swift不允许定义两个相同形参列表的构造器, 即使一个是可能失败的构造器, 一个是普通构造器也不行
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)
print(p1)
class Person {
var name: String?
var gender: String?
var age = 0
// 由于该类中前2个实例存储属性使用了可选类型, 后1个实例存储属性指定了初始值
// 因此该结构体对构造器没有要求, 故此处可随便定义一个带参数的构造器
// 取消构造器参数的外部形参名
init(_ name: String, _ gender: String) {
self.name = name
self.gender = gender
}
}
// 调用构造器时无需使用外部形参名
var p = Person("孙悟空", "男")
print(p.name)
print(p.gender)
print(p.age)
class User1 {
var maxAge = 100
var name: String
init (maxAge: Int, name: String) {
print(self.maxAge)
self.maxAge = Int.max
print(self.maxAge)
self.name = name
self.maxAge = maxAge
}
}
var u = User1(maxAge: 120, name: "白骨精")
print(u.maxAge)
print(u.name)
struct closureInit {
// 使用闭包对test实例存储属性执行初始化
var test: Int = {
var dt = NSDate()
// 定义一个时间字段的旗标, 指定将会获取指定日,月信息
var gregorian = NSCalendar.currentCalendar()
// 获取日月的旗标
var unitFlags = NSCalendarUnit.Month
var unitFlags1 = NSCalendarUnit.Day
var comp = gregorian.component(unitFlags, fromDate: dt)
var comp1 = gregorian.component(unitFlags1, fromDate: dt)
// 获取当前的月份
var month = Int(comp)
// 获取当前的第几日
var day = Int(comp1)
// 得到计算结果
return day - month
}()
}
var ci = closureInit()
print(ci.test)
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: "HelloWorld", amount: 8000000)
print("\(oc1.name) \(oc1.amount)")
print("\(oc2.name) \(oc2.amount)")
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) {
// name = "临时值" // 这行代码将导致错误
self.init(n, c) // 构造器代理
// 调用构造器代理之后, 即可通过self访问该实例的数学
print("--执行显式指定外部形参名的构造器---\(self.name)")
}
// 定义三个参数的构造器
init(name: String, color: String, weight: Double) {
self.init(name, color) // 构造器代理
self.weight = weight
}
}
var ap1 = Apple("红富士", "粉红色")
print("\(ap1.name) ---> \(ap1.color)")
var ap2 = Apple(appleName: "青苹果", appleColor: "青色")
print("\(ap2.name) ---> \(ap2.color)")
var ap3 = Apple(name: "山东苹果", color: "红色", weight: 0.5)
print("\(ap3.name) ---> \(ap3.color)")
struct Cat {
let name: String
init?(name: String) {
// 如果传入的name参数为空字符串, 构造器失败, 返回nil
if name.isEmpty {
return nil
}
self.name = name
}
}
let c1 = Cat(name: "Kitty")
if c1 != nil {
// 创建c1的构造器时init?, 因此程序必须对c1执行强制解析
print("c1的name为:\(c1!.name)")
}
let c4 = Cat(name: "")
print(c4 == nil) // 输出ture, 表明c2为nil
enum Season3 {
case Spring, Summer, Autumn, Winter
// 使用init!定义可能失败的构造器, 则该构造器创建的实例可进行隐式解析
init!(name: Character) {
// 根据传入的构造器参数选择相应的枚举成员
switch name {
case "S", "s":
self = .Spring
case "U", "u":
self = .Summer
case "A", "a":
self = .Autumn
case "W", "w":
self = .Winter
// 如果传入其他参数, 构造失败, 返回nil
default:
return nil
}
}
}
let s1 = Season3(name: "s")
if s1 != nil {
print("Season3实例构造成功!")
}
let s2 = Season3(name: "x")
print(s2 == nil)