当前位置: 首页>编程语言>正文

swift5.5语法

1.swift3.0以后,去除了自增(++)和自减(--)的运算符,替代成了-=+=

 func TestDemo() {
        var num = 5
        while num > 0 {
            print("打印了了\(num)次")
            num -= 1
        }
    }

2.区间运算符 注意对应的符号,一定是3个点, 2个点的是半区间,字符串也能使用区间运算符,但是不能再for in中使用

  • 半区间运算符 1...3
  • 闭区间运算符 1..<3
  • 单侧(方向)区间:[...3] [3...]

3.区间类型

  let range: ClosedRange<Int>  = 1...3
  let range2: Range<Int> = 1..<3
  let range3: PartialRangeThrough<Int> = ...5

3.switch注意点

case default至少要有一条语句,如果不需要,加个break即可
如果能保证已处理所有情况,可以不必使用default

4.switch和enum的标准用法

  • enum虽然有其他简便写法,但是此种是最标准的
- 
public enum SelectedBarVerticalAlignment {
    case top
    case middle
    case bottom
}

switch selectedBarVerticalAlignment {
        case .top:
            selectedBarFrame.origin.y = 0
        case .middle:
            selectedBarFrame.origin.y = (frame.size.height - selectedBarHeight) / 2
        case .bottom:
            selectedBarFrame.origin.y = frame.size.height - selectedBarHeight
        }

枚举相关概念:
1.枚举成员可以使用相同类型的默认值预先对应, 这个值默认叫做原始值
2.如果枚举的原始值类型是Int String ,swift会自动分配原始值, 这个叫:隐式原始值
3.原始值不占用枚举变量的内存

5.swift中的访问控制关键字

  • private 私有访问控制 只允许当前类中调用
  • fileprivate(不常用) 其修饰的属性或者方法只能在当前的 Swift 源文件里可以访问
  • public修饰的属性或者方法可以在其他作用域被访问,但不能在override 和 继承方法中的 Extension 中被访问
  • open在override 和 继承方法中的 Extension 中可以被访问
    总结:原来 Swift 中有2种常用访问控制关键字(访问控制修饰符),分别为 private 和 public。而在 Swift 3.0+,又在原来的基础上新增了两种:fileprivate、open。它们可以看成是对 private 和 public 的进一步细分

6.空合并运算符(常用)

高级语法中的 两个问号?: 意思是:如果数据不存在,则为后面的值

var optionalInt: Int?
let result: Int = optionalInt ?10 result = 10

var optionalInt: Int= 20
let result: Int = optionalInt ?10 result = 20

// if let 与 结合使用
let a: Int= nil
let b: Int= 2
if let c = a ?b {
   print(c)
}

6.guide语句

读几遍:
guard 语句的条件为false, 就会执行大括号里面的代码
guard 语句的条件为true, 就会跳过guard语句
guard语句进行可选性绑定时,绑定的let var能在外层作用域中使用
总结: 判断条件不符合的高级写法,优化了OC的判断特性

guard <#condition#> else {
            <#statements#>
        }

7.结构体和类

吐槽:初学感觉类和结构体傻傻分不清(忽略) 精简分析一下:不一笔带过

结构体分析:

  • 在swift标准库中,绝大多数的公开类型都是结构体,而枚举和类只占很小一部分
  • 比如Bool, Int, Double, String, Array, Dictionary等常见类型都是结构体
  • 所有的结构体,编译器都会根绝情况为结构体自动生成多个初始化器,但是类是不会生成初始化器
  • 自定义初始化器时,编译器无法自动生成其他初始化器

类的分析:

  • 类中所有成员在定义时,指定了初始值,编译器才会为类生成无参的初始化器

类和结构体的本质区别:

  • 类是引用类型(指针类型),引用赋值给var, let或者函数传参是将内存地址拷贝一份,属于浅拷贝
  • 结构体和枚举是值类型,值类型赋值给var, let或者函数传参是将所有内容,产生了新的副本,属于深拷贝

注意:
初始化器的作用:保证所有的成员都有初始值
枚举,结构体,类都可以定义方法

8.属性

swift 中实例相关的属性可以分类2大类
存储属性:

  • 存储在实例的内存中
  • 结构体,类可以定义存储属性,枚举不可以
  • 延迟存储属性lazy:
    1.第一次用到的时候,属性才会初始化,lazy属性必须是var ,let必须在初始化完成之前拥有初始值
    2.如果多条线程同时第一次访问lazy属性,无法保证属性只被初始化一次
    计算属性:
  • 本质就是方法(函数)
  • 计算属性不占用实例内存
  • 定义计算属性只能用var,不能用let
 struct Circle {
        // 存储属性
        var radius: Double
        // 计算属性
        var diamater:Double {
            set {
                radius = newValue / 2
            }
            get {
                radius * 2
            }
        }
    }

9.属性观察器 willSet 和 didSet 现身

可以为非lazyvar存储属性设置属性观察器

  • willSet会传递新值,默认叫newValue
  • didSet会传递旧值,默认叫oldValue
  • 初始化器设置属性值不会触发
  • 在属性定义时设置初始值也不会触发
  • 可以应用在全局或局部变量身上
    struct Circle {
        // 存储属性
        var radius: Double {
            willSet {
                
            }
            didSet {
                
            }
        }
    }

10.inout关键字

inout的本质: 引用传递(地址传递)

11. 类型属性

  • 实例属性 :只能通过实例去访问,每个实例都有一份内存
  • 类型属性 :整个程序运行过程中,就只有1份内存(类似于全局变量)
    1.通过static定义类型属性, 也可以通过class定义, 整个程序运行过程中,就只有一份内存(类似于全局变量)
    2.存储类型属性必须设定初始值
    细节:
    存储属性分为:
  • 实例属性:
  • 类型属性:
    1.必须设定初始值(因为类型没有实例那样的init初始器来初始存储类型)
    2.类型属性默认是lazy,会在第一次使用的时候才初始化(就算被多个线程访问,也只会初始化一次)
    3.类型属性可以是let

12. 方法

枚举 结构体 类都可以定义实例方法和类方法

  • 实例方法:通过实例对象调用
  • 类型方法:通过类型调用,用static 和 class 关键字定义
  • self 在实例方法中代表是实例对象, 在类型中代表是类
  • mutating: 结构体和枚举是值类型, 值类型的属性不能被自身的实例方法修改, 如果要修改在fun关键字前加mutating
  • discardableResult 消除调用后返回值未被使用的警告

13.下标

下标是用于访问集合、列表或序列的成员元素的快捷方式。可以使用下标,设置和获取值,而不用单独的调用对应的存取
下标语法

subscript(index: Int) -> Int {
    get {
      // 返回一个适当的 Int 类型的值
    }

    set(newValue) {
      // 执行适当的赋值操作
    }
}

下标用法:

class Student: NSObject {

    var name = ""
    var age = 10
    var height = 170
    
    subscript(index:Int) -> AnyObject{
        switch index{
        case 0:
            return name as AnyObject
        case 1:
            return age as AnyObject
        case 2:
            return height as AnyObject
        default:
            return name as AnyObject
        }
    }
}

//调用
let stu = Student()
stu.name = "海王"
print(stu[0])  //海王
print(stu[1])  //10
print(stu[2])  //170

14.继承

  • 值类型不支持继承,只有类才可以继承
  • 子类可以重写父类的 方法 下标 属性 ,重写时加上关键字override
  • class修饰的类方法,下标,允许被子类重写
  • static修饰的类方法,下标,不允许被子类重写
  • 子类可以把父类属性重写为计算属性
  • 子类不可以把父类属性重写为存储属性
  • 只能重写var属性,不能重写let属性
  • 重写后的属性权限不能小于父类属性
  • final修饰的方法, 下标, 属性 不能被重写
  • final修饰的类不能被继承关系

15.初始化器

有两种:

  • 便利初始化器
  • 指定初始化器
    required修饰指定初始化器,表明所有子类都必须实现出初始化器,如果子类重写了requierd初始化器,也必须加上requierd,不用加override

属性观察器:
父类的属性在自己的初始化器中赋值不会触发属性观察期,但是在子类的初始化器中赋值会触发属性观察期

可失败初始化器(不常用):
类,结构体,枚举可以使用init?定义可失败初始化器

  • 如果初始化器调用一个可失败初始化器导致初始化失败,那么整个初始化过程都失败,并且之后的代码都停止执行
  • 可以用init!定义隐式解包的可失败初始化器

反初始化器

  • deinit叫做反初始化器,类似于OC中的dealloc方法
  • 当类的实例对象被销毁内存时,就会调用实例对象的deinit方法
  • 父类的deinit可以被子类继承
  • 子类的deinit执行完毕后会调用父类的deinit

16.可选链

使用可选值有时会让人感到有点笨拙,所有的解包和检查会变得如此繁重,以至于会让你想要丢几个感叹号上去强制解包,好让你能继续工作下去。但是请小心:如果你强制解包一个没有值的可选值,你的代码就崩了

func albumReleased(year: Int) -> String{
    switch year {
    case 2006: return "Taylor Swift"
    case 2008: return "Fearless"
    case 2010: return "Speak Now"
    case 2012: return "Red"
    case 2014: return "1989"
    default: return nil
    }
}

let album = albumReleased(year: 2006)?.uppercased()
print("The album is \(album)")

  • 注意这里有个“问号”,这就是可选链:在“问号”后的所有代码,只会在“问号”前的代码有值时,才会运行。
  • Swift 将会从左到右检查它们,直到遇到一个 nil 后停止。如下
let album = albumReleased(year: 2006)?.someOptionalValue?.someOtherOptionalValue?.whatever

17.协议

协议可以定义属性,方法, 下标。
协议可以被类,结构体,枚举遵循

protocol YPPhotoCapture: class {
    
    // Public api
    func start(with previewView: UIView, completion: @escaping () -> Void)
    func stopCamera()
    func focus(on point: CGPoint)
    func zoom(began: Bool, scale: CGFloat)
    func tryToggleFlash()
    var hasFlash: Bool { get }
    var currentFlashMode: YPFlashMode { get }
    func flipCamera(completion: @escaping () -> Void)
    func shoot(completion: @escaping (Data) -> Void)
    var videoLayer: AVCaptureVideoPreviewLayer! { get set }
    var device: AVCaptureDevice{ get }
    
    // Used by Default extension
    var previewView: UIView! { get set }
    var isCaptureSessionSetup: Bool { get set }
    var isPreviewSetup: Bool { get set }
    var sessionQueue: DispatchQueue { get }
    var session: AVCaptureSession { get }
    var output: AVCaptureOutput { get }
    var deviceInput: AVCaptureDeviceInput{ get set }
    var initVideoZoomFactor: CGFloat { get set }
    func configure()
}
  • 协议不指定是否该属性应该是一个存储属性或者计算属性,它只指定所需的属性名称和读写类型。属性要求总是声明为变量属性,用var关键字做前缀

  • 要求该属性的读写权限(可读可写或者可读)

  • mutating关键字 : mutating关键字放在方法func关键字之前,表明该方法允许修改所属实例的任何属性

  • @escaping关键字:逃逸闭包

  • 协议SomeProtocol中不光可以声明方法/属性/下标,还可以声明构造器,但在Swift中,除了某些特殊情况外,构造器是不被子类继承的,所以SomeClass中虽然能够保证定义了协议要求的构造器,但不能保证SomeClass的子类中也定义了协议要求的构造器。所以我们需要在实现协议要求的构造器时,使用required关键字确保SomeClass的子类必须也得实现这个构造器。

  • Optional协议要求只有在你的协议被@objc属性标记时指定。
    即使你不与Objective-C交互,如果你希望指定optional要求,你仍然需要使用@objc标记你的协议。
    使用@objc标记的协议只能通过类调用

18.Any于AnyObject的区别

  • 两者都可以表示OC中的id 任意类型
  • AnyObject用于任何类(class)的实例,而Any可以用于表示任何类型,包括基本类型、值类型以及实例
  • 应该尽量多使用泛型少用Any,避免转换类型是发生的类型错误

https://www.xamrdz.com/lan/5qn2016176.html

相关文章: