Swift
变量常量与基本类型
// 常量
let pi = 3.14
// 变量
var i = 1, j = 2
// 显式变量类型
var url: String = "www.baidu.com"
// 整型 取决于机器字长
print(Int.max)
// 无符号整型
print(UInt.max)
// 8位整型
print(Int8.max)
// 浮点数
let x: Float = 3.1415926
let y: Double = 3.155645
print(x, y)
// 不支持隐式转换
print(x+Float(y))
// 元组
var property: (String, Int, (Int, Int, Int)) = ("cxk", 18, (35, 35, 35))
print(property)
print(property.0)
print(property.1)
// 元组的比较
print((1,2,3) < (3,2,1))
// 解构
let (name, age, quake) = property
// 解构忽略部分属性
let (name1, age1, _) = property
print(name, age, quake)
// 命名元组属性
var point: (x: Int, y: Int) = (1,2)
var point1 = (x:1, y: 2)
print("the point: \(point), point1: \(point1)")
运算符
基本的数值逻辑运算符操作跟 Java 一样, 但在 Swift3 之后 ++ -- 已被废弃
=== 与 !== 用来比较对象的引用
常量的首次赋值
let i: Int
var condition = false
if condition {
i = 1
}else {
i = 2
}
范围运算符
let a = 0..<10 // 前闭后开(0-9)
print(a)
// 前闭后闭(1-10)
for index in 1...10 {
print(index)
// 循环里的index是常量
// index += 1
}
控制流
循环
- for 循环
// 忽略下标
for _ in 1...10 {
print("gogogo")
}
- while 循环
var i = 1
// i的后面一定要有空格
while i <= 10 {
print(i)
i += 2
}
- do-while循环
var j = 1
repeat {
print(j)
j += 2
}while(j <= 10)
选择
if 同类C语言
switch
// 每条case之间不用加break
var rank = "a"
switch rank {
// 同时case多个条件
case "a", "A":
print("jn")
case "b":
print("d")
default:
print("defa")
// 空语句
//default:break
//default:()
}
// switch与范围
switch 5 {
case 1...5:
print("1-5")
case 6...10:
print("6-10")
default:()
}
// switch与元组
let response = (200, "OK")
switch response {
case(200, "OK"):
print("done")
case(200, "GOON"):
print("continue")
default:()
}
// 在case中解构变量
switch (0,0) {
case(let x, 0):
print("x is \(x)")
case (0, let y):
print("y is \(y)")
default:()
}
// 继续往下执行
switch 5 {
case 5:
print("5")
// 不会判断下面的case是否满足条件 无脑执行
fallthrough
case 6:
print("6")
default:()
}
控制转移
// 跳出多重循环
outter:
for index in 1...10{
for index1 in 1...10 {
if (index == 3 && index1 == 3) {
print("i got go")
break outter
}
}
}
where
// where类似于SQL中的where 是一种条件限定
switch (3,3){
case let(x,y) where x == y:
print("x == y")
case let(x,y):
()
}
for case let index in 1...10 where index % 3 == 0 {
print(index)
}
guard
// 防御式编程的语义化
// 只有满足条件才不会进入代码块
guard num >= 1 else {
print("stop")
exit(0)
}
字符串
基础
// 判断是否是空字符串
print(str.isEmpty)
// 插值表达式
print("name: \(str)")
// 字符串拼接 转义字符等同类C语言
char与unicode
// 显式声明单个字符(底层采用unicode存储)
let single: Character = "中"
let single1: Character = "🐶"
// 遍历字符
for c in "中文大萨达🇨🇳" {
print(c)
}
// 字符串是可变的
str.append("jntm")
print(str)
// 字符串长度
print(str.count)
索引
- 挺难用的
// 字符串索引
// [startIndex, endIndedx)
var s = "我如果付费"
// 需要根据startIndex 或者endIndex 计算
print(s[s.index(s.startIndex, offsetBy: 2)]) // 果 在第一个索引往后的2个
print(s[s.index(before: s.endIndex)]) // 费 在最后一个索引之前的一个
方法
print(s.uppercased())
print(s.lowercased())
print(s.capitalized) // 将每个单词转为首字母大写
print(s.contains("如果"))
print(s.hasPrefix("我 "))
print(s.hasSuffix("费"))
NSString
print(NSString(format: "%.2f", 1.0 / 3.0) as String)
// 截取
print(NSString("微分去问问").substring(with: NSMakeRange(1, 3)))
// 替换两边的字符
print(NSString("-a-").trimmingCharacters(in: CharacterSet(charactersIn: "-")))
可选型
var responseCode : Int? = 404
var responseMessage: String? = "success"
responseCode = nil
var code: Int! = 4
let a = code // 此时a的类型是Int?
let b: Int = code // 可以转为Int
解包
// 强制解包
print(responseCode!)
// 在判断中解包
if let responseCode = responseCode {
// 这里出现了变量遮蔽
print(responseCode)
}
// 同时判断解包多个
if let responseCode = responseCode,
let responseMessage = responseMessage {
print(responseCode, responseMessage)
}
可选型链
if let responseMessage = responseMessage {
print(responseMessage.uppercased)
}
// 等同于
print(responseMessage?.uppercased)
// 如果是 nil 则 message 的值 为 message null
let message = responseMessage ?? "message null"
在类库中的使用
// 类型转换 如果转换失败 就返回 nil
if let age = Int("18"), age <= 18 {
print(age)
}
隐式可选型
// 一般用在类中 初始化时为空 当初始化完成 保证对外提供的不为 nil
var a: String! = nil
// a = "hello"
// 执行错误
print(a + "dsds")
数组
声明
var nums = [0,1,2,3]
// 指定类型
var strings: [String] = ["0","2", "a"]
// 空数组
var es : Array<Int> = []
var es1 = [Int]()
// 5个元素初始值 全为5
var allZeros = [Int](repeating: 5, count: 5)
基本操作
print(allZeros.count)
print(allZeros.isEmpty)
// 数组越界会有运行异常
print(allZeros[3])
print(allZeros.first!, allZeros.last!)
print(nums.min()!, nums.max()!)
// 子数组 1,2,3
print(nums[1..<4])
print(nums.contains(3))
print(nums.firstIndex(of: 3)!)
// for-each
for number in nums {
print(number)
}
// 带下标的for-each
for (index, item) in strings.enumerated() {
print(index, item)
}
// 值比较
print(nums == [0,1,2,3])
修改
es.append("jntm")
// 添加两个元素到数组里面
es += ["cxk", "juki"]
// 插入后位于索引2
es.insert("ctrl", at: 2)
es.removeLast()
es.removeFirst()
// 删除指定下标
es.remove(at: 1)
es.removeAll()
nums[0] = 3
// 区间设置值
nums[0...2] = [9,9,9]
// 两边长度可以不一致
nums[0...2] = [7]
NSArray
// 可以承载不同数据类型
var na: NSArray = [1, "hello", 3]
集合
字典
var dict: [String: String] = ["name": "cxk", "age": "18"]
var dict1: Dictionary<String, String> = [:]
print(dict["name"]!)
print(Array(dict.keys))
print(Array(dict.values))
for key in dict.keys {
print(dict[key]!)
}
for (key, value) in dict {
print(key, value)
}
print(dict == ["name": "cxk", "age": "18"])
// 更新
dict["name"] = "jntm"
// 这个方法会返回其之前的值
dict.updateValue("jntm", forKey: "name")
// 删除
dict["name"] = nil
dict.removeValue(forKey: "name")
dict.removeAll()
Set
// 声明
var set : Set<String> = ["a", "b" , "c"]
for i in set {
print(i)
}
print(set == ["b", "c", "a"])
set.insert("aa")
set.remove("c")
// 集合运算
print(set.union(["a","aa"]))
print(set.intersection(["a", "aa"]))
print(set.subtracting(["a", "aa"]))
print(set.symmetricDifference(["a", "aa"]))
函数
定义
// 有参数有返回值
func say(name: String, age: Int) -> String {
return "jntm \(name) - \(age)"
}
// 无参数无返回值
func say() {
print( "ctrl")
}
// 返回多个值
func request() -> (message: String, code: Int) {
return ("not found", 404)
}
// 调用时 多个参数必须使用 形参: 实参 的形式
print(say(name: "cxk", age: 18))
外内部参数名
// 外部与内部参数名
func request(url getUrl: String) {
print(getUrl)
}
request(url: "http://baidu.com")
// 忽略外部参数名
func request(_ url: String, _ method: String) {}
request("baidu.com", "get")
默认参数、可变参数
// 可变参数不像其他语言 可以不放在最后 可变参数本质上也是一个数组
func request(url: String, method: String = "get", params: String ...){}
request(url: "baidu.com", params: "sds", "dfsds")
引用参数
// 默认参数值和可变参数
// 可变参数不像其他语言 可以不放在最后 可变参数本质上也是一个数组
func request(url: String, method: String = "get", params: String ...){}
request(url: "baidu.com", params: "sds", "dfsds")
// 形参默认都是不可变的
// 使用 inout 关键字 相当于一个指针
func request(url: inout String){
url = "google.com"
}
var u = "dsds"
request(url: &u)
print(u)
函数式编程
func submit(runnable: () -> ()) {
runnable()
}
func print(){
print("running")
}
// 第一种调用
submit(runnable: print)
// 第二种调用
submit {
print("hhh")
}
// 传递一个参数
func submit(consumer: (String) -> ()){
consumer("ikun")
}
submit { params in
print(params)
}
// 函数式编程三大操作
print([1,2,3].map{ v in v + 1})
print([1,2,3].filter{ v in v % 2 == 0})
print([1,2,3].reduce(10, {x, y in x + y}))
// 返回函数类型
func getFuture() -> () -> () {
return {
print("this is future")
}
}
getFuture()()
// 函数嵌套
func execute(){
func innerFunc(){
print("hello world")
}
innerFunc()
}
execute()
闭包
var res = [1, 2, 3].sorted(by: { (a: Int, b: Int) -> Bool in
return a > b
})
print(res)
// 化简
print([1,2,3].sorted(by: {a, b in a > b}))
// 默认命名
print([1, 2, 3].sorted(by: {$0 > $1}))
// 大于号本身是一个函数
print([1,2,3].sorted(by: >))
// 结尾闭包 最后一个参数是闭包的话 可以使用这种语法
print([1,2,3].sorted{ a, b in a > b})
print([1,2,3].map{v in String(v)})
// 内容捕获
var num = 700
print([1,2,3].sorted{a , b in abs(a-num) < abs(b-num)})
// @autoclosure 自动将值封装成匿名函数
func test(f: @autoclosure () -> String) -> String {
return f()
}
test(f: "test")
枚举
enum Color: String {
case Red = "红色",Yellow = "黄色",Blue = "蓝色"
}
let color: Color = .Blue
switch color {
case .Blue:
print(color.rawValue)
case .Yellow:
print(color.rawValue)
case .Red:
print(color.rawValue)
}
// 使用rawValue获取枚举值
print(Color(rawValue: "红色")!)
// 关联值
enum Status {
case Success(message: String, code: Int)
case Error(String)
}
let result = Status.Success(message: "done", code: 200)
switch result {
case let .Success(message, _):
print("sucess \(message)")
case .Error:
print("error")
}
// 可选型的本质就是使用了关联值的枚举
let name: String? = Optional.some("jntm")
switch name {
case let .some(name):
print(name)
case .none:
print("is nil")
}
结构体
struct Location {
// 这里var跟let的区别在于是否可变
var x = 0,y: Int = 0
var z: Int = 0
init() {}
init(x: Int, y: Int, z: Int) {}
init(x: Int, y: Int) {
self.x = x
self.y = y
}
// 可失败的构造函数 返回nil
init?(x: Int) {
guard x <= 100 else {
return nil
}
self.x = x
}
func distance() -> Int {
return x - y
}
// 如果不加mutating这个关键字 这个方法就没法修改结构体
mutating func setX(x: Int) {
self.x += 1
}
}
var home = Location(x: 1, y: 2, z: 3)
// 如果里面的字段有默认值 在这里的构造可以传参
var empty = Location()
print(Location(x: 4, y: 3))
print(home.x)
print(Location(x:101) ?? -1)
home.x = 2
print(home.distance())
// 结构体和枚举是值类型
var p1 = Location(x: 1, y: 2)
var p2 = p1
p1.x = 3
print(p2.x == 1)
类
class Person {
static var popilation: Int = 700_0000_0000
var name: String
var age: Int {
// 属性观察器 需要注意的是不会在init阶段被调用
// 将要赋值
willSet {
if newValue > 200 {
print("太太老")
}
}
// 已经赋值了
didSet {
if age == 18 {
print("貌美如花")
}
if age > 100 {
print("太老了")
age = oldValue
}
}
}
// 计算属性
var nameAndAge: String {
get{
return name + "," + String(age)
}
set(nameAndAge) {
self.name = nameAndAge.components(separatedBy: ",")[0]
self.age = Int(nameAndAge.components(separatedBy: ",")[1])!
}
}
var bithYear: Int {
return 2022 - self.age
}
// 延迟属性 首次访问时会被计算后缓存下来
lazy var firstDate: Date = {
return Date()
}()
init(name: String, age: Int) {
self.name = name
self.age = age
}
init?(nameAndAge: String) {
if !nameAndAge.contains(",") {
return nil
}
self.name = nameAndAge.components(separatedBy: ",")[0]
self.age = Int(nameAndAge.components(separatedBy: ",")[1])!
}
// 类型方法
static func populationBalanced() -> Bool {
return popilation <= 7000_0000_0000
}
}
// 类创建的对象是引用类型
let cxk = Person(name: "cxk", age: 18)
print(cxk.age)
print(Person(nameAndAge: "cxk,18")!.age)
// cxk本身如果是常量 但里面的成员是变量 则可以修改 不像结构体
cxk.age = 22
// 继承
class Student: Person {
var grade = 12
// 重载构造器
// 使用required关键字来强制子类必须重写该构造函数
required init(grade: Int) {
// 在super.init之前 不能做self初始化之外的操作
// self.eat()
super.init(name: "cxk", age: 17)
self.grade = grade
}
// 便利构造函数 通过一定逻辑调用其他构造函数初始化
// 便利构造器无法调用super.init
// 如果子类实现了父类所有的指定构造函数,则自动继承父类的所有便利构造函数
convenience init(){
self.init(name: "jntm", age: 22)
}
// 重写构造器
override init(name: String, age: Int) {
super.init(name: name, age: age)
self.name = name
self.age = age
}
// 重写属性
override var bithYear: Int {
return 2023 - self.age
}
// 重写方法
override func eat() {
print("student eat")
}
}
// 禁止再继承
final class SuperPerson: Person{}
let student = Student(grade: 12)
print(student.nameAndAge)
// 多态
let persons: [Person] = [SuperPerson(nameAndAge: "s1,14")!, Student(grade: 18), Person(nameAndAge: "s1,32")!]
访问控制:
- public 可在模块外访问
- internal 默认的控制 可在本模块内访问
- private 只允许在本文件内访问
运算符重载
// 自定义运算符需要声明 postfix prefix infix
infix operator |||
struct ReversedList {
var data: [Int] = [1,2,3,4,5]
// 重载下标运算符
subscript(index: Int) -> Int? {
get {
data[data.count - index - 1]
}
set {
if let newValue = newValue {
data[data.count - index - 1] = newValue
}
}
}
// 多维下标
subscript(index1: Int, index2: Int) -> Int {
return data[index1] + index2
}
// 算术运算符重载
static func + (left: ReversedList, right: ReversedList) -> ReversedList {
return ReversedList(data: left.data + right.data)
}
static func + (left: ReversedList, right: Int) -> ReversedList {
var left = left
for i in 0..<left.data.count {
left.data[i] += right
}
return left
}
static func += (left: inout ReversedList, right: Int) {
left = left + right
}
prefix static func - (left: ReversedList) -> ReversedList {
return ReversedList(data: left.data.map {-$0})
}
// 比较运算符重载
static func == (left: ReversedList, right: ReversedList) -> Bool {
guard left.data.count == right.data.count else {
return false
}
for i in 0..<left.data.count {
if (left.data[i] != right.data[i]) {
return false
}
}
return true
}
static func < (left: ReversedList, right: ReversedList) -> Bool {
for i in 0..<left.data.count {
if left.data[i] >= right.data[i] {
return false
}
}
return true
}
// 自定义运算符 /,=,-,+,!,*,%,<,>,&,|,^,~
static func ||| (left: ReversedList, right: ReversedList) -> ReversedList {
var left = left
for i in 0..<left.data.count {
left.data[i] = left.data[i] % right.data[i]
}
return left
}
}
扩展
extension String {
// 如果扩展类的构造方法 则构造方法必须是便利构造方法
init(by: String) {
self.init(by.uppercased())
}
// 扩展的属性只能是计算型属性
var length: Int {
self.count
}
func firstChar() -> Character {
return self[self.startIndex]
}
// 嵌套类型
struct Range {}
}
let range : String.Range? = nil
泛型
// 泛型函数
func swap<T>(a: inout T, b: inout T) {
(a,b) = (b,a)
}
var a = "123"
var b = "321"
swap(a: &a, b: &b)
print(a,b)
// 泛型类型
struct ArrayList<T> {
var data: [T] = []
mutating func add(e: T) {
data += [e]
}
}
var list = ArrayList<String>()
list.add(e: "123")
print(list)
协议
protocol Runnable {
// 协议的属性
var threadName: String {get set}
// 协议的方法
func run()
}
struct Task: Runnable {
var threadName = "test"
func run() {
print("running")
}
}
// 只有类才能实现该协议
protocol Future: AnyObject {}
class MyFuture: Future{}
// 如果既需要继承有需要协议 则继承类要放在协议的前面
class Callable: NSObject, Future {}
// 类型别名
typealias Length = Int
let length: Length = 123
// 类型参数化
protocol WeightCalacuable {
associatedtype WightType
var weight: WightType {get}
}
class Phone: WeightCalacuable {
typealias WightType = Double
var weight = 0.114
}
class Boat: WeightCalacuable {
typealias WightType = Int
var weight = 100_0000
}
标准库的常用协议:Equatable, Comparable, CustomStringCovertible
面向协议编程
// 扩展协议
protocol Callable: Runnable{
func call() -> Int
}
// 协议的默认实现
extension Callable {
func run() {
let _ = self.call()
}
}
// 限定扩展:只有同时实现Callable和WeightCalacuable才应用
extension Callable where Self: WeightCalacuable {
func run() {
print("calc run")
}
}
struct Computer: Callable, WeightCalacuable {
var weight: Int
func call() -> Int {
return 0
}
typealias WightType = Int
var threadName: String
}
Computer(weight: 1, threadName: "test").run()
// 协议聚合:同时实现两种协议的参数才被接受
func run(computeable: Callable & CustomStringConvertible){}
// 泛型约束
func topOne<T: Comparable & CustomStringConvertible>(seq: [T]) -> T {
let ans = seq.sorted()[0]
print(ans.description)
return ans
}
print(topOne(seq: [67,6,4,23,45,2,1]))
// 协议的可选方法
@objc protocol Service {
@objc optional func start()
}
class UserService: Service{}
let service: Service = UserService()
if let start = service.start {
start()
}
错误处理
enum RuntimeError: Error{
case NetWorkError(String)
case ReadTimeOutError
}
func main(a: Int) throws -> Void {
// 函数执行结束后才会执行
defer {
print("finally2 execute")
}
defer {
print("finally1 execute")
}
if a == 1 {
throw RuntimeError.NetWorkError("unknow host")
}
}
// 强制忽略异常 发生异常程序就会崩
try! main(a:2)
// 忽略异常 发生异常不会蹦
try? main(a: 1)
do {
try main(a: 1)
}catch RuntimeError.NetWorkError(let e) {
print("error", e)
}catch let e as RuntimeError {
print(e)
}catch {
print("unknow error")
}
// 使用Nerver代表异常情况
func errorHandle() -> Never {
print("!!!")
fatalError()
}
var aaa = 1
guard aaa != 1 else {
errorHandle()
}
内存管理
class Pet {
var owner: Person?
init(owner: Person) {
self.owner = owner
}
deinit{
print("pet clean")
}
}
class Person {
// 没有加weak时会出现相互引用导致内存泄漏 加了weak后不会增加pet的引用数
// weak要求类型是可选型并且是var的 如果不满足这个条件 需要使用unowned
// 但unowned有一定的风险 如果一个unowned被回收后被使用 则会发生致命错误
weak var pet: Pet?
init() {
pet = Pet(owner: self)
}
deinit {
print("person clean")
}
}
// swift 使用引用计数
var p: Person? = Person()
p = nil
对于闭包循环引用 可以使用 [unoned xxx] 的方式来声明闭包内的变量为弱引用
类型检查与转换
class Animal{}
class Duck: Animal{}
class Dog: Animal{}
let dog: Animal = Dog()
// 类型检查
print(dog is Dog)
// 尝试强制转型 失败返回nil
print((dog as? Dog)!)
Any > AnyObject > NSObject