一. 常量&变量的使用注意
1.注意一:
在开发中,优先使用常量(let). 只有发现标识符需要修改时,再使用变量.选择let更加安全
目的: 防止在其它不希望修改的地方,不小心将值修改掉
2.注意二:
常量的本质: 指向的内存地址不可以修改,但是可以通过内存地址找到对应的对象,之后修改对象内部的属性
OC中创建对象:
UIView *view = [[UIView alloc] init];
Swift中创建对象:
类型()
var view : UIView = UIView()
view = UIView()
1> 指向的内存地址不可以修改
let view : UIView = UIView() // 0x100
view = UIView() // 0x200
2> 但是可以通过内存地址,找到对应的对象,之后修改对象内部的属性
view.alpha = 0.5
view.backgroundColor = UIColor.blue
二. 创建对象补充
UIButton = UIButton()
btn.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
btn.backgroundColor = UIColor.orange
btn.setTitle("按钮", for: .normal)
view.addSubview(btn)
三、 类型推导
类型推导
1> 如果在定义一个标识符时,有直接给该标识符进行赋值. 那么可以将标识符后面的类型省略掉
2> 编译器会根据我们后面赋值的类型,自动推导出前面标识符的类型, 这个过程就叫做类型推导
3> 可以通过 option + 鼠标左键 来查看标识符的类型
四、基本运算
不同类型之间不能直接计算,(OC可以,因为有隐式转换)
let m = 20
let n = 10.5
错误写法:
let result = m + n
正确写法:
将Int类型转成Double: Double(标识符)
将Double类型转成Int : Int(标识符)
let result1 = Double(m) + n
let result2 = m + Int(n)
注:类型转换实质就是调用构造函数转换类型
五、逻辑分支(if的使用)
OC的语法
int a = 20
if (a > 0) { }
if (a) { }
Swift中if和OC的区别
1> if后面的()可以省略掉,执行分支必须有{}
2> 没有非0)即真的概念,只有Bool(true/false)
let a = 10
if a > 0 {
print("a大于0")
}
if a != 0 {
print("a不等于0")
}
else if的使用
let score = 88
if score < 0 || score > 100 {
print("不合理的分数")
} else if score < 60 {
print("不及格")
} else if score < 80 {
print("及格")
} else if score < 90 {
print("良好")
} else {
print("优秀")
}
六、逻辑分支(guard的使用)
可以理解为给判断条件取反,与 if!() 类似
let age = 20
func online(age : Int) {
if age >= 18 {
if 带了身份证 {
if 带了钱 {
print("可以上网")
} else {
print("回家拿钱")
}
} else {
print("回家拿身份证")
}
} else {
print("回家去")
}
}
func online(age : Int) {
// guard : 守卫
// 1.判断年龄是否大于18岁
guard age >= 18 else {
print("回家去")
return
}
// 2.判断是否带了身份证
guard 带了身份证 else {
print("回家拿身份证")
return
}
// 3.判断是否带了钱
guard 带了钱 else {
print("回家拿钱")
return
}
print("留下上网")
}
online(age: age)
七、逻辑分支(switch的使用)
1.switch基本使用
1> switch后面的()可以省略
2> case语句结束时,可以不加break,默认不穿透,如果需要穿透需要添加fallthrouth关键字
3> 一次性可以判断多个条件
4> 可以判断任意类型的对象
let sex = 1
// sex 0 : 男 1 : 女
switch sex {
case 0:
print("男")
case 1:
print("女")
default:
print("其它")
}
2.基本用法补充
1> 在swift中,switch后面case可以判断多个条件
2> 如果希望case结束时,产生case穿透.case结束时,加上fallthrough
switch sex {
case 0, 1:
print("正常人")
fallthrough
default:
print("非正常人")
}
3.switch判断其它类型
3.1.判断浮点型
let m = 3.14
switch m {
case 3.14:
print("和π相等")
default:
print("和π不相等")
}
3.2.判断字符串
let a = 20
let b = 30
let oprationStr = "*"
var result = 0
switch oprationStr {
case "+":
result = a + b
case "-":
result = a - b
case "*":
result = a * b
case "/":
result = a / b
default:
print("不合理的操作符")
}
3.3.判断区间类型
let score = 88
switch score {
case 0..<60:
print("不及格")
case 60..<80:
print("及格")
case 80..<90:
print("良好")
case 90...100:
print("优秀")
default:
print("不合理的分数")
}
八、循环使用(for循环)
OC语法
for (int i = 0; i < 10; i++) {
NSLog(@"%d", i);
}
Swift语法
for i in 0..<10 {
print(i)
}
for i in 0...10 {
print(i)
}
在swift开发中,如果一个变量/常量暂暂时不会使用,那么可以使用 _ 通配符 来代替
for _ in 0..<10 {
print("hello world")
}
九、循环使用(while&dowhile循环)
OC语法
int a = 0
while (a < 10) {
a++
}
swift中while循环和OC区别
1> while后面()可以省略
2> 没有非0(nil)即真 Bool(true/false)
var m = 0
while m < 10 {
m += 1
print(m)
}
repeat {
m -= 1
print(m)
} while m > 0
十、字符串的使用
String字符串类型,通过结构体实现的,更加轻量级,支持快速遍历,NSString中的并不支持,String可以和NSString无缝的转换
NSString继承NSObiect是一个对象,不支持遍历
1.定义字符串
1> 定义不可变字符串 : 使用let修饰
let str : String = "hello swift"
let str = "Hello Swift"
2> 定义可变字符串 : 使用var修饰
var strM = "Hello World"
strM = "Hello China"
2.获取字符串的长度
let length = str.characters.count
3.字符串的拼接
3.1.字符串之间的拼接
let str1 = "我很帅"
let str2 = ",真的很帅!"
// OC拼接方式 [NSString stringwithFormat:@"%@%@", str1, str2];
let str3 = str1 + str2
3.2.字符串和其它标识符之间的拼接
let name = "NIE"
let age = 19
let height = 1.87
let infoStr = "my nams is \(name), age is \(age), height is \(height)"
3.3.字符串拼接过程中的格式化: 03:04
let min = 3
let second = 50
let timeStr = String(format: "%02d:%02d", min, second)
4.字符串的截取
let urlString = "www.baidu.com"
4.1.方式一:(建议使用此方式)
将String类型转成NSString类型,再进行截取: as NSString
let header1 = (urlString as NSString).substring(to: 3)
let range1 = NSMakeRange(4, 5)
let middle1 = (urlString as NSString).substring(with: range1)
let footer1 = (urlString as NSString).substring(from: 10)
4.2.方式二:
直接使用String类型方法,进行截取
let headerIndex = urlString.index(urlString.startIndex, offsetBy: 3)
let header2 = urlString.substring(to: headerIndex)
let startIndex = urlString.index(urlString.startIndex, offsetBy: 4)
let endIndex = urlString.index(urlString.startIndex, offsetBy: 9)
let range = Range(startIndex..<endIndex)
let middle2 = urlString.substring(with: range)
let footerIndex = urlString.index(urlString.endIndex, offsetBy: -3)
let footer2 = urlString.substring(from: footerIndex)
十一、数组的使用
1.数组的定义
数组的类型:
1> Array<String>
2> [String] (推荐)
let array = ["MM", "NN", "HH"]
var arrayM = Array<String>()
var arrayM = [String]()
2.对可变数组的基本操作
增:
arrayM.append("nienie")
arrayM.insert("杰克", at: 0)
删:
arrayM.remove(at: 0)
arrayM.removeFirst()
arrayM.removeLast(2)
改:
arrayM[0] = "LL"
查:
let item = arrayM[0]
3.对数组的遍历
3.1.获取数组的长度
let count = array.count
3.2.对数组进行遍历(可以获取到下标值)
for i in 0..<count {
print(array[i])
}
3.3.对数组进行遍历(不需要获取下标值)
for item in array {
print(item)
}
3.4.对数组进行遍历(既获取下标值,又获取元素)
for (index, item) in array.enumerated() {
print(index, item)
}
3.5倒序遍历
for name in array.reversed() {
print(name)
}
4.数组的合并
如果两个数组中存放的是相同的元素,那么在swift中可以对两个数组进行相加,直接合并
let array1 = ["AA", "BB"]
let array2 = ["CC", "DD"]
let array3 = [12, 20, 30]
let resultArray = array1 + array2
let result = array1 + array3 错误写法
十二、字典的使用
1.如何定义字典
编译器会根据[]中是一个个元素(数组),还是键值对(字典)
let dict = ["name" : "AA", "age" : 18, "height" : 1.88] as [String : Any]
let dict = ["123" : "321", "abc" : "cba"] 不需要进行转化
Array<String> --> [String]
let dict : Dictionary<String, Any> = ["name" : "AA", "age" : 18, "height" : 1.88]
let dict : [String : Any] = ["name" : "AA", "age" : 18, "height" : 1.88]
泛型字典类型:
[String : String]
2> 定义可变字典 : 使用var修饰
var arrayM = [String]()
var dictM = Dictionary<String, Any>()
var dictM = [String : Any]()
2.对可变字典的基本操作(增删改查)
增:
dictM["name"] = "AA"
dictM["age"] = 18
dictM["height"] = 1.88
删:
dictM.removeValue(forKey: "height")
改:
dictM["name"] = "BB"
dictM.updateValue("BB", forKey: "name")
查:
dictM["age"]
3.遍历字典
3.1.遍历字典中所有的key
for key in dict.keys {
print(key)
}
3.2.遍历字典中所有的value
for value in dict.values {
print(value)
}
3.3.遍历字典中所有的key/value
for (key, value) in dict {
print(key, value)
}
4.字典合并
var dict1 : [String : Any] = ["name" : "AA", "age" : 18]
let dict2 : [String : Any] = ["height" : 1.88, "phoneNum" : "+86 110"]
let resultDict = dict1 + dict2
或:
for (key, value) in dict2 {
dict1[key] = value
}
十三、元组的使用
1.使用数组保存信息
let infoArray : [Any] = ["why", 18, 1.88]
let arrayName = infoArray[0] as! String
print(arrayName.characters.count)
2.使用字典保存信息
let infoDict : [String : Any] = ["name" : "why", "age" : 18, "height" : 1.88]
let dictName = infoDict["name"] as! String
print(dictName.characters.count)
3.使用元组保存信息(取出数据时,更加方便)
3.1.写法一:
let infoTuple = ("AA", 18, 1.88)
let tupleName = infoTuple.0
let tupleAge = infoTuple.1
print(tupleName.characters.count)
3.2.写法二:
let infoTuple1 = (name : "AA",age : 18, height : 1.88)
infoTuple1.age
3.3.写法三:
let (name, age, height) = ("AA", 18, 1.88)
十四、可选类型的使用
一个对象都会有两面性,即有值或为nil
在开发中,只有可选类型才能赋值为nil, 其它类型都不能赋值为nil
在类型的后面添加'?'声明可选类型 例:
var a : Int?
常量的可选类型是没有意义的,因为只有一次赋值机会
必选类型,一定要有值,并且一定不能为nil
可选类型不能够直接参与计算
'?'表示可选类型
在打印的时候会自动带上Optional字样
'!'
可选类型不能够直接计算,如果参与计算系统会自动提示添加'!'强制解包
将'可选类型'的值,解包
报错fatal(致命的) error: unexpectedly found nil while unwrapping() an Optional value
'!'存在风险,如果为nil,程序就会boom
提示程序员在这个地方可能存在风险需要考虑是否需要判断为nil
'??'
空合并运算符得到的结果是必选类型
运算符的优先级比较低,在使用的时候需要使用()来提高优先级
相当于三目运算符
快速判断对象是够为nil,如果为nil,就去??后面设置的默认值
带有红圈白点的错误提示,一般都是系统能够自动修改的错误
1.定义可变类型: 泛型集合
1> 定义方式一:
var name : Optional<String> = nil
2> 定义方式二: 语法糖
var name : String? = nil
2.给可选类型赋值
2.1.赋值方式一:
name = Optional("AA")
2.2.赋值方式二:
name = "AA"
3.取出可选类型中的值
从可选类型中取值: 可选类型 + ! --> 强制解包
print(name!)
4.注意: 强制解包非常危险, 如果可选类型为nil,那么强制解包就会崩溃
if name != nil {
print(name!)
}
5.可选绑定(固定格式) : 该语法用于可选类型, 使我们使用起来可选类型更加方便
1> 判断name是否有值, 如果没有值,则直接不执行{}
2> 如果name有值,那么系统会自动对可选类型进行解包, 并且将解包后的结果赋值给前面的tempName
if let tempName = name {
print(tempName)
}
if let name = name {
print(name)
}
十五、可选类型的应用
只要一个类型有可能为nil, 那么这个标识符的类型一定是一个可选类型
1.将字符串转成Int类型
let m : Double = 2.44
let n = Int(m)
let str : String = "123"
let num : Int? = Int(str) // 123/nil
2.根据文件名称:123.plist, 获取该文件的路径
let path : String? = Bundle.main.path(forResource: "123.plist", ofType: nil) // string/nil
3.将字符串转成NSURL
如果字符串中有中文,那么就是转化不成功, 返回结果 nil
let url : NSURL? = NSURL(string: "http://www.520it.com") // URL/nil
let url = URL(string: "http://www.520it.com")
4.从字典中取出元素
let dict : [String : Any] = ["name" : "why", "age" : 18]
let value = dict["neme"] // Any/nil
十六、类型转化
1.之前的as使用
let str = "www.xunjian.com"
(str as NSString).substring(to: 11)
2.as? as! --> 将Any类型转成具体类型
let dict : [String : Any] = ["name" : "AA", "age" : 18, "height" : 1.88]
2.1. as? 的用法
通过as?转成可选类型
as? : 转成的类型是一个可选类型, 系统会自动判断tempName是否可以转成String, 如果可以转成, 那么获取字符串, 如果转化不成功, 则返回nil
let tempName = dict["name"]
let name = tempName as? String
if let name = name { // 可选绑定
print(name)
}
if let name = dict["name"] as? String {
print(name)
}
2.2. as! 的用法
通过as!转成具体类型
as! : 将类型转成具体的类型
注意: 如果转化不成功, 则程序会直接崩溃
建议: 如果确定转化成功,再用as!, 平时不建议
let tempName1 = dict["name"]
let name1 = tempName1 as! String
十七、函数的使用
1.没有参数,没有返回值的函数
func about() -> Void {
print("iPhone8")
}
func about1() {
print("iPhone8")
}
about()
2.有参数,没有返回值的函数
func callPhone(phoneNum : String) {
print("打电话给:\(phoneNum)")
}
callPhone(phoneNum: "+86 110")
3.没有参数,有返回值的函数
func readMsg() -> String {
return "吃饭了吗?"
}
let msg = readMsg()
print(msg)
4.有参数,有返回值的函数
func sum(num1 : Int, num2 : Int) -> Int {
return num1 + num2
}
let result = sum(num1: 20, num2: 30)
print(result)
十八、函数的其他用法
1.内部参数&外部参数
内部参数: 在函数内部能看到标识符名称, 该标识符就是内部参数
外部参数: 在函数外部能看到标识符名称, 该标识符就是外部参数
默认情况下,所有的参数都是内部参数,也是外部参数
修改外部参数: 在标识符前加上外部参数名称即可
如果不希望显示外部参数, 可以在标识符前加上 _
func sum(_ num1 : Int, _ num2 : Int) -> Int {
return num1 + num2
}
let result = sum(num1: 20, num2: 30)
let result = sum(abc: 20, num2: 30)
let result = sum(20, 30)
2.可变参数
func sum(_ nums : Int...) -> Int {
var total = 0
for n in nums {
total += n
}
return total
}
3.默认参数
func makeCoffee(coffeeName : String = "雀巢") -> String {
return "制作了一杯:\(coffeeName)咖啡"
}
makeCoffee(coffeeName: "拿铁")
makeCoffee(coffeeName: "猫屎")
makeCoffee()
4.指针参数
var m : Int = 20
var n : Int = 30
func swapNum(num1 : inout Int, num2 : inout Int) {
let temp = num1
num1 = num2
num2 = temp
}
swapNum(num1: &m, num2: &n)
print("m:\(m) n:\(n)")
十九、枚举类型
1.枚举类型的定义
enum MethodType : String {
case get = "get"
case post = "post"
case put = "put"
case delete = "delete"
}
2.创建枚举具体的值
let type1 : MethodType = .get
let type2 = MethodType.post
let type3 = MethodType(rawValue: "put") // 值/nil
let str = type3?.rawValue
3.给枚举类型进行赋值
enum Direction : Int {
case east = 0
case west = 1
case north = 2
case south = 3
}
let d1 : Direction = .east
let d2 = Direction(rawValue: 1)
4.枚举类型定义方式二:
enum Type : Int {
case get = 0, post, put, delete
}
二十、结构体的使用
1.定义结构体
struct Location {
// 属性
var x : Double
var y : Double
var z : Double
// 方法
// 最普通的函数: 该函数是没有用到成员属性
func test() {
print("结构体中的test函数")
}
// 改变成员属性 : 如果在函数中修改了成员属性, 那么该函数前必须加上mutating
mutating func moveH(_ distance : Double) {
self.x += distance
}
给结构体扩充构造函数
1> 默认情况下, 系统会为每一个结构体提供一个默认的构造函数, 并且该构造函数, 要求给每一个成员属性进行赋值
2> 构造函数都是以init开头, 并且构造函数不需要返回值
3> 在构造函数结束时, 必须保证所有的成员属性有被初始化
init(x : Double, y : Double) {
self.x = x
self.y = y
}
init(xyStr : String) {
// 20,30 --> ["20", "30"]
let array = xyStr.components(separatedBy: ",")
let item1 = array[0]
let item2 = array[1]
/*
if let x = Double(item1) {
self.x = x
} else {
self.x = 0
}
if let y = Double(item2) {
self.y = y
} else {
self.y = 0
}
*/
// ?? 判断前面的可选类型是否有值
// 有值, 则解包, 没有值,则使用后面的值
self.x = Double(item1) ?? 0
self.y = Double(item2) ?? 0
}
}
2.创建结构体对应的值
var center = Location(x: 20, y: 30)
let ceter = Location(x: 20, y: 30, z: 40)
3.系统结构体的创建方式
let rect = CGRect(x: 0, y: 0, width: 100, height: 100)
let size = CGSize(width: 20, height: 20)
let point = CGPoint(x: 0, y: 0)
let range = NSRange(location: 0, length: 3)
4.给结构体扩充方法
center.test()
//center.moveH(distance: 20)
center.moveH(20)
print(center)
5.给结构体扩充构造函数
Location(x: 20, y: 30)
Location(xyStr : "20,30")
二十一、类的使用
1.如何定义类
OC类的定义:
@interface Person : NSObject
@end
@impelment
@end
Swift类的定义:
class Person {
// 类的属性定义
// 存储属性: 用于存储实例的常量&变量
var name : String = ""
var age : Int = 0
var mathScore : Double = 0.0
var chineseScore : Double = 0.0
// 计算属性: 通过某种方式计算得来结果的属性,就是计算属性 --> 只读属性
var averageScore : Double {
return (chineseScore + mathScore) * 0.5
}
// 类属性: 和整个类相关的属性, 并且是通过类名进行访问
static var courseCount : Int = 0
// 给类扩充函数
// 在OC中写的很多没有参数的方法, 在swift中可以写成计算属性
func getAverageScore() -> Double {
return (chineseScore + mathScore) * 0.5
}
}
二十二、监听类的属性改变
class Person {
var name : String = "" {
// 属性监听器: 选中其中之一即可
// 监听属性即将发生改变: 还没有改变
willSet(newName) {
print(newName)
print(name)
}
// 监听属性已经发生改变: 已经改变
didSet(oldName) {
print(oldName)
print(name)
}
}
}
let p = Person()
p.name = "AA"
二十三、类的构造函数
构造函数类似于OC中的初始化方法:init方法
默认情况下载创建一个类时,必然会调用一个构造函数
即便是没有编写任何构造函数,编译器也会提供一个默认的构造函数。
如果是继承自NSObject,可以对父类的构造函数进行重写
类的属性必须有值,如果不是在定义时初始化值,可以在构造函数中赋值
OC的方法:
@interface Person : NSObject
@property (nonautomic, copy) NSString *name;
@property (nonautomic, assign) NSInteger age;
- (instanceType)initWithName:(NSString *)name age:(NSInteger)age;
- (instanceType)initWithDict:(NSDictionary *)dict;
@end
Person *p = [Person alloc] init];
Person *p = [Person alloc] initWithName:@"why" age:18];
Swift的方法:
方法一:重写了NSObject(父类)的构造方法
类的属性必须有值,如果不是在定义时初始化值,可以在构造函数中赋值
class Person: NSObject {
var name : String
var age : Int
// 重写了NSObject(父类)的构造方法
override init() {
name = ""
age = 0
}
}
// 创建一个Person对象
let p = Person()
方法二: 初始化时给属性赋值
很多时候,我们在创建一个对象时就会给属性赋值,可以自定义构造函数
注意:如果自定义了构造函数,会覆盖init()方法.即不再有默认的构造函数
class Person: NSObject {
var name : String
var age : Int
// 在Swift开发中, 如果在对象函数中, 用到成员属性, 那么self.可以省略
// 注意: 如果在函数中, 有和成员属性重名的局部变量,那么self.不能省略
// 注意: 如果有自定义构造函数, 那么会将系统提供的构造函数覆盖掉
// 自定义构造函数,会覆盖init()函数
init(name : String, age : Int) {
self.name = name
self.age = age
}
}
// 创建一个Person对象
let p = Person(name: "who", age: 18)
方法三:字典转模型(初始化时传入字典)
真实创建对象时,更多的是将字典转成模型
注意:
去字典中取出的是NSObject,任意类型.
可以通过 as! 转成需要的类型,再赋值(不可以直接赋值)
class Person: NSObject {
var name : String
var age : Int
// 自定义构造函数,会覆盖init()函数
init(dict : [String : NSObject]) {
name = dict["name"] as! String
age = dict["age"] as! Int
}
}
// 创建一个Person对象
let dict = ["name" : "who", "age" : 18]
let p = Person(dict: dict)
方法四:字典转模型(利用KVC转化)
利用KVC字典转模型会更加方便
注意:
KVC并不能保证会给所有的属性赋值
因此属性需要有默认值
基本数据类型默认值设置为0
对象或者结构体类型定义为可选类型即可(可选类型没有赋值前为nil)
使用KVC条件
1> 必须继承自NSObject
2> 必须在构造函数中,先调用super.init()
3> 调用setValuesForKeys
4> 如果字典中某一个key没有对应的属性, 则需要重写setValue forUndefinedKey方法
class Person: NSObject {
// 结构体或者类的类型,必须是可选类型.因为不能保证一定会赋值
var name : String?
// 基本数据类型不能是可选类型,否则KVC无法转化
var age : Int = 0
// 自定义构造函数,会覆盖init()函数
init(dict : [String : NSObject]) {
// 必须先初始化对象
super.init()
// 调用对象的KVC方法字典转模型
setValuesForKeysWithDictionary(dict)
}
}
// 创建一个Person对象
let dict = ["name" : "who", "age" : 18]
let p = Person(dict: dict)
三十四、类的析构函数
Swift 会自动释放不再需要的实例以释放资源,通过自动引用计数(ARC)处理实例的内存管理,当引用计数为0时,系统会自动调用析构函数(不可以手动调用)
通常在析构函数中释放一些资源(如移除通知等操作)
析构函数的写法
deinit {
// 执行析构过程
}
class Person {
var name : String
var age : Int
init(name : String, age : Int) {
self.name = name
self.age = age
}
// 重写析构函数, 监听对象的销毁
deinit {
print("Person-deinit")
}
}
var p : Person? = Person(name: "cj", age: 18)
p = nil
三十五、循环引用
// 1.创建类
class Person {
var name : String = ""
var book : Book?
deinit {
print("Person -- deinit")
}
}
class Book {
var price : Double = 0
/*
OC中表示弱引用
__weak/__unsafe_unretained(野指针错误)
Swift中表示弱引用
weak/unowned(野指针错误)
*/
// weak var owner : Person?
// unowned 不能用于修饰可选类型
unowned var owner : Person = Person()
deinit {
print("Book -- deinit")
}
}
// 2.创建两个对象
var person : Person? = Person()
person!.name = "AA"
var book : Book? = Book()
book!.price = 60.0
person!.book = book
book!.owner = person!
person = nil
book = nil
三十六、可选链的使用场景
class Person {
var dog : Dog?
}
class Dog {
var toy : Toy?
}
class Toy {
var price : Double = 0
func flying() {
print("飞盘在飞ing")
}
}
let p = Person()
let d = Dog()
let t = Toy()
t.price = 100
p.dog = d
d.toy = t
可选链的使用
?.代表可选链: 系统会自动判断该可选类型是否有值;如果有值,则解包;如果没有值, 则赋值为nil
注意: 可选链条获取的值,一定是一个可选类型
if let price = p.dog?.toy?.price { // Double/nil
print(price)
}
let price = p.dog?.toy?.price
如果可选链中有一个可选类型是没有值, 那么语句直接不执行
p.dog?.toy?.price = 50
可选链调用方法
p.dog?.toy?.flying()
三十七、协议的使用
协议的定义
protocol SportProtocol {
// 默认情况下协议中的方法都是必须实现的方法
func playBasketball()
func playFootball()
}
2.定义类,并且遵守协议
class Teacher : SportProtocol {
func playFootball() {
print("踢足球")
}
func playBasketball() {
print("打篮球")
}
}
class Student : NSObject, SportProtocol {
func playFootball() {
print("踢足球")
}
func playBasketball() {
print("打篮球")
}
}
3.协议在代理设计模型中的使用
定义协议时, 协议后面最好跟上 : class
delegate的属性最好用weak, 防止产生循环引用
protocol BuyTicketDelegate : class {
func buyTicket()
}
class Person {
// 定义代理属性
weak var delegate : BuyTicketDelegate?
func goToBeijing() {
delegate?.buyTicket()
}
}
4.协议方法可选
optional属于OC特性, 如果协议中有可选的方法, 那么必须在protocol前面加上@objc, 也需要在optional前面加上@objc
@objc protocol TestProtocol {
@objc optional func test()
}
class Dog : TestProtocol {
func test() {
}
}
网友评论