简单记录一些自己容易忘记的碎片化的点
一、tips
1、swift中文名雨燕
2、不用编写main函数,将全局范围内首句可执行代码作为程序入口
3、一句代码尾部可以省略分号,多句代码写到同一行必须用分号隔开
4、var定义变量,let定义常量,编译器能够自动推断出变量和常量的类型
二、常见数据类型
Swift常见数据类型.png三、函数文档注释
///
/// 求和【概述】
///
/// 将两个整数相加【更加详细的描述】
///
/// - Parameter a: 参数a描述
/// - Parameter b: 参数b描述
/// - Returns :两个整数的和
///
/// - Note:传入两个整数即可【批注】
///
func sum(a: Int, b: Int) -> Int {
a + b
}
调用的时候,按住option,点击函数名即可出现下图的注释效果:
注释.png
MARK / TODO / FIXME
- MARK: 类似于OC中的 #pragma mark
- MARK: - 类似于OC中的 #pragma mark - (预览的时候跟上个相同级别的标注之间会有线隔开,见下面图片中灰色线条)
- TODO: 用于标记未完成的任务
- FIXME: 用于标记待修复的问题
-
warning("undo"):如果觉得 TODO: 不够明显, 可以考虑用这个
// MARK: - 私有方法
// MARK: test1方法
private func test1() {
// TODO: 未完成
}
// MARK: test2方法
private func test2() {
// FIXME: 有待修复的问题
}
// MARK: - 公共方法
// MARK: test3方法
public func test3() {}
// MARK: test4方法
public func test4() {}
// 警告,会在代码中有明显的黄色叹号提示
#warning("undo")
注释.png
四、参数
1、可以修改参数标签
func gotoSchool(at time: String) {
print("go to school \(time)")
}
gotoSchool(at: "08:00")
2、可以使用下划线_ 省略参数标签,相对复杂的尽量不要省略
func sum(_ a: Int, _ b: Int) -> Int {
a + b
}
print(sum(10, 20))
3、参数类型后面加上三个点表示可变参数,可以传多个对应类型的参数
需要注意的问题:
1、一个函数最多只能有一个可变参数
2、紧跟在可变参数后面的参数不能省略参数标签
func sum(_ numbers: Int...) -> Int {
var total = 0
for number in numbers {
total += number
}
return total
}
print(sum(10, 20, 30, 40)) // 100
五、Optional-可选项
可选项,一般也叫可选类型,它允许将值设置为nil,在类型名称后面加个?来定义一个可选项
var name: String? = "Jack"// 不写= "Jack",默认就是nil
name = nil
可选项是对其它类型的一层包装,如果要从可选项中取出被包装的数据,需要使用感叹号!进行强制解包
let count: Int? = 10
var countAdd: Int = count!
countAdd += 10
print(countAdd)
如果对值为nil的可选项进行强制解包,会产生运行时错误,程序直接崩溃
let count: Int?
// 如果count为nil,强制解包程序会crash
count!
// 在实际开发中我们一般会这样做
if let temp = count {
// 在这里进行处理
print(temp)
}
可选项的本质是 enum 类型,下面两种写法完全等价
let a: Int? = 10
let b: Optional<Int> = .some(10)
六、运算符
1、??:合并空值运算符
a ?? b
(1)用于判断常量或者变量的值是否为nil,如果为nil,则取后面的值,不为nil,取前面的值。有点儿类似三目运算符
(2)上面的表达式,如果a有值,则取a,如果a为nil,则取b
应用示例:
func sum(a: Int?, b: Int?) -> Int {
// 方法一:如果a或者b有nil,则程序会crash
return a! + b!
//方法二:判断条件太多,容易遗漏
if a != nil {
if b != nil {
return a! + b!
} else {
return a!
}
} else {
if b != nil {
return b!
} else {
return 0
}
}
//方法三:简洁、安全
return (a ?? 0) + (b ?? 0)
}
2、reversed():倒序索引
for i in (0...9).reversed() {
print(i)
}
// 输出结果
9
8
7
6
5
4
3
2
1
0
3、 (逗号)
做判断的时候在两个条件中间加一个 相当于 &&
let a: Int = 11
// 判断1 和 判断2 等价
// 判断1
if a > 0, a > 11 {
print(123)
}
// 判断2
if a > 0 && a > 11 {
print(123)
}
七、guard
guard语句,有点儿类似if语句,但是后面会一直跟着else语句,并且else里面的语句只有在guard条件不为真的时候才执行。下面两段代码是检测ip地址是否正确,第一段用if实现,第二段用guard实现。
// 试用if判断ip地址是否正确
func checkIpAddress(ipAddress: String) -> (Int, String) {
// 用点来分割ip地址
let compoment = ipAddress.split(separator: ".")
if compoment.count == 4 {
if let first = Int(compoment[0]), first >= 0 && first < 256 {
if let second = Int(compoment[1]), second >= 0 && second < 256 {
if let third = Int(compoment[2]), third >= 0 && third < 256 {
if let fourth = Int(compoment[3]), fourth >= 0 && fourth < 256 {
return (100, "ip地址是正确的")
} else {
return (4, "ip地址第四部分不对")
}
} else {
return (3, "ip地址第三部分不对")
}
} else {
return (2, "ip地址第二部分不对")
}
} else {
return (1, "ip地址第一部分不对")
}
} else {
return (0, "ip地址必须有四部分")
}
}
// 试用guard判断ip地址是否正确
func checkIpAddress(ipAddress: String) -> (Int, String) {
let compoment = ipAddress.split(separator: ".")
guard compoment.count == 4 else {
return (0, "ip地址必须有四部分")
}
guard let first = Int(compoment[0]), first >= 0 && first < 256 else {
return (1, "ip地址第一部分不对")
}
guard let second = Int(compoment[1]), second >= 0 && second < 256 else {
return (2, "ip地址第二部分不对")
}
guard let third = Int(compoment[2]), third >= 0 && third < 256 else {
return (3, "ip地址第三部分不对")
}
guard let fourth = Int(compoment[3]), fourth >= 0 && fourth < 256 else {
return (4, "ip地址第四部分不对")
}
return (100, "ip地址是正确的")
}
八、字符串
1、首字母大写:capitalized
let str = "hello world"
print(str.capitalized)
// 输出:Hello World
2、字符全部转大写
let str = "hello world"
print(str.uppercased())
// 输出:HELLO WORLD
3、字符全部转小写
let str = "HeLLo WoRlD"
print(str.lowercased())
// 输出:hello world
九、数组
1、以逗号拼接字符串数组所有元素为一个字符串
let arr = ["you", "only", "live", "once"]
let newArr = arr.joined(separator: ",")
print(newArr)
// 输出
you,only,live,once
2、字符串转数组
let str = "you only live once"
let arr = str.components(separatedBy: " ")
print(arr)
// 输出
["you", "only", "live", "once"]
十、输入输出参数(In-Out Parameter)
可以用inout定义一个输入输出参数,在函数内部修改外部变量的值
inout的本质是地址传递(引用传递)
inout参数不能有默认值
可变参数不能标记为inout
inout参数的传入值能被多次赋值
func swapValue(_ v1: inout Int, _ v2: inout Int) {
let tmp = v1
v1 = v2
v2 = tmp
}
var num1 = 10
var num2 = 20
swapValue(&num1, &num2)
print(num1, num2)
// 打印结果
// 20 10
十一、可变参数
参数类型后面加三个点表示可变参数
一个函数最多只能有1个可变参数
紧跟在可变参数后面的参数不能省略参数标签
func sum(_ numbers: Int..., other: Int) -> Int {
var total = 0
for item in numbers {
total += item
}
return total + other
}
let result = sum(1, 2, 3, 4, other: 5)
print(result)
// 打印结果
// 15
十二、属性
严格来说,属性可以按下面方式划分
-
实例属性(Instance Property)
1.存储实例属性(Stored Instance Property)存储在实例的内存中,每个实例都有1份
2.计算实例属性(Computed Instance Property) -
类型属性(Type Property)
1.存储类型属性(Stored Type Property)整个程序运行过程中,就只有1份内存(类似于全局变量)
2.计算类型属性(Computed Type Property)
十三、mutating
结构体和枚举是值类型,默认情况下,值类型的属性不能被自身的实例方法修改
在 func 关键字前加 mutating 可以允许这种修改行为
// 结构体
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(_ deltaX: Double, _ deltaY: Double) {
x += deltaX
y += deltaY
}
}
// 枚举
enum StateSwitch {
case low, middle, high
mutating func next() {
switch self {
case .low:
self = .middle
case .middle:
self = .high
case .high:
self = .low
}
}
}
十四、@discardableResult
调用有返回值的方法,如果没有使用返回的值,会有一个黄色的警告,如果想消除这个警告,可以在方法前面加上 @discardableResult
注:除非特殊需求,建议非必要不要使用
@discardableResult func add(_ a: Int, _ b: Int) -> Int {
a + b
}
// 这样直接调用就不会有警告了
add(10, 3)
十五、class & static & final
1、被class修饰的类型方法、下标,允许被子类重写
被static修饰的类型方法、下标,不允许被子类重写
2、被class修饰的计算类型属性,可以被子类重写
被static修饰的类型属性(存储、计算),不可以被子类重写
3、被 final 修饰的方法、下标、属性,禁止被重写
被final修饰的类,禁止被继承
十六、(+) (-)
Swift 编译器特性
// 两个 Int 类型参数相加、相减
let dic: [String: (Int, Int) -> Int] = [
"sum": (+),
"minus": (-)
]
let result1 = dic["sum"]?(10, 5)
let result2 = dic["minus"]?(12, 5)
print(result1)
print(result2)
十七、Any / AnyObject
- Any:可以代表任意类型(枚举、结构体、类、也包括函数类型)
- AnyObject:可以代表任意 类 类型(在协议后面加上:AnyObject,代表只有类能遵守和这个协议)
十八、数组、字典声明
// 下面两种声明数组的方法完全等价
var arr = Array<Int>()
var arr = [Int]()
// 下面两种声明字典的方法完全等价
var dic = Dictionary<Int, Int>()
var dic = [Int: Int]()
十九、is、as、as?、 as!
i s 用来判断是否为某种类型, as用来做类型强制转换
二十、访问控制(Access Control)
在访问权限控制这块,Swift提供了5个不同的访问级别,以下是从高到低排列,实体指的是被访问级别修饰的内容
- open:允许在定义实体的模块,其它模块中访问,允许其它模块进行继承、重写(open只能用在类、类成员上)
- public:允许在定义实体的模块、其它模块中访问、不允许其它模块进行继承、重写
- internal:只允许在定义实体的模块中访问,不允许在其它模块中访问
- fileprivate:只允许在定义实体的源文件中访问
- private:只允许在定义实体的封闭声明中访问
注:绝大部分实体默认都是 internal 级别
二十一、API可用性说明
比如你自己封装了一个三方框架,但是在升级过程中有的API被废弃掉,或者已过期,可以进行下面的操作
struct Student {
// 方法名重命名
@available(*, unavailable, renamed: "study")
func study1() {}
func study() {}
// 方法在iOS被废弃掉
@available(iOS, deprecated: 11)
func run() {}
}
let stu = Student()
// 会提示 'run()' was deprecated in iOS 11
stu.run()
// 会提示 'study1()' has been renamed to 'study'
stu.study1()
网友评论