美文网首页
Swift笔记

Swift笔记

作者: 小二郎_Ejun | 来源:发表于2019-02-25 20:39 被阅读7次

    Swift中weak与unowned的区别

    在闭包里面为了解决循环引用问题,使用了 [unowned self]。如果回调在self已经被释放后再调用,会导致crash掉。

    解决:使用weak修饰。

    weak与unowned的区别:
    unowned设置以后即使它原来引用的内容已经被释放了,它仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil 。如果你尝试调用这个引用的方法或者访问成员属性的话,程序就会崩溃。而 weak 则友好一些,在引用的内容被释放后,标记为 weak 的成员将会自动地变成 nil (因此被标记为 @ weak 的变量一定需要是 Optional 值)。

    map、flatMap、filter、reduce

    map:转换,可以对数组中的元素格式进行转换

    //将Int数组转换为String数组
    //$0代表数组的元素
    let array = [1, 2, 3, 4, 5 , 6, 7]
    let result = array.map{
      String($0)
    }
    

    flatMap与map不同之处:

    (1)flatMap返回后的数组中不存在nil,同时它会把Optional解包
    (2)flatMap还能把数组中存有数组的数组(二维数组、N维数组)一同打开变成一个新的数组
    (3)flatMap也能把两个不同的数组合并成一个数组,这个合并的数组元素个数是前面两个数组元素个数的乘积

    let fruits = ["Apple", "Orange", "Puple"]
    let counts = [2, 3, 5]
    
    let array = counts.flatMap { count in
        fruits.map ({ fruit in
             return fruit + "  \(count)"            
        })   
    }
    array // ["Apple 2", "Orange 2", "Puple 2", "Apple 3", "Orange 3", "Puple 3", "Apple 5", "Orange 5", "Puple 5"]
    

    filter:过滤,可以对数组中的元素按照某种规则进行过滤

    //在array中过滤出偶数
    let result2 = array.filter{ 
      $0 % 2 == 0
    }
    

    reduce:计算 ,可以对数组中的元素进行计算

    //计算数组array元素的和
    //在这里$0和$1的意义不同,$0代表元素计算后的结果,$1代表元素
    //10代表初始化值,在这里可以理解为 $0初始值 = 10
    let result3 = array.reduce(10){  
      $0 + $1
    }
    

    逃逸闭包与非逃逸闭包

    在Swift 3 后,传递闭包到函数中的时候,系统会默认为非逃逸闭包类型 (Nonescaping Closures)@noescape,有非逃逸闭包类型必然就有逃逸闭包(Escaping Closures),逃逸闭包在闭包前要添加@escaping关键字

    非逃逸闭包的生命周期:1.把闭包作为参数传给函数;2.函数中调用闭包;3.退出函数,闭包生命周期结束

    即非逃逸闭包的生命周期与函数相同

    逃逸闭包的生命周期:1.闭包作为参数传递给函数;2.退出函数; 3.闭包被调用,闭包生命周期结束

    即逃逸闭包的生命周期长于函数,函数退出的时候,逃逸闭包的引用仍被其他对象持有,不会在函数结束时释放

    经常使用逃逸闭包的2个场景:

    异步调用: 如果需要调度队列中异步调用闭包,比如网络请求成功的回调和失败的回调,这个队列会持有闭包的引用,至于什么时候调用闭包,或闭包什么时候运行结束都是不确定,上边的例子。
    存储: 需要存储闭包作为属性,全局变量或其他类型做稍后使用,例子待补充。

    关键字详解

    关键字是类似于标识符的保留字符序列,除非用重音符号(`)将其括起来,否则不能用作标识符。关键字是对编译器具有特殊意义的预定义保留标识符。
    常见的关键字有以下4种。

    **与声明有关的关键字**:class、deinit、enum、extension、func、import、init、let、protocol、static、struct、subscript、typealias和var。

    **与语句有关的关键字**:break、case、continue、default、do、else、fallthrough、if、in、for、return、switch、where和while。

    **表达式和类型关键字**:as、dynamicType、is、new、super、self、Self、Type、COLUMNFILEFUNCTIONLINE

    **在特定上下文中使用的关键字**:associativity、didSet、get、infix、inout、left、mutating、none、nonmutating、operator、override、postfix、precedence、prefix、rightset、unowned、unowned(safe)、unowned(unsafe)、weak和willSet。

    final

    final关键字可以在class、func和var前修饰。表示 不可重写 可以将类或者类中的部分实现保护起来,从而避免子类破坏
    Swift - final关键字的介绍,以及使用场景

    static

    static关键字声明静态变量或者函数,它保证在对应的作用域当中只有一份, 同时也不需要依赖实例化。注意:(用static关键字指定的方法是类方法,他是不能被子类重写的

    mutating

    mutating关键字指的是可变即可修改。用在structure和enumeration中,虽然结构体和枚举可以定义自己的方法,但是默认情况下,实例方法中是不可以修改值类型的属性。为了能够在实例方法中修改属性值,可以在方法定义前添加关键字mutating

    struct rect {
            var width = 0,height = 0
            mutating func changeRect(x:Int, y:Int) {
                self.width += x
                self.height += y
            }
            
        }
        
       
        enum Direction {
            case Top, Left, Right, Bottom
            mutating func lookDirection() {
                switch self {
                case .Top:
                    self = .Top
                case .Left:
                    self = .Left
                case .Right:
                    self = .Right
                case .Bottom:
                    self = .Bottom
                }
                print("self === \(self)")
            }
        }
    
    
        var re = rect(width: 5, height: 5)
            re.changeRect(x: 32, y: 15)
            print("re = \(re)")
            
            /**
             打印结果为:re = rect(width: 37, height: 20)
             */
            
            var dir = Direction.Left
            dir.lookDirection()
            /**
             打印结果为:self === Left
             */
    

    required

    required是用来修饰init方法的,说明该构造方法是必须实现的

    class PerSon {
            var name:String
            required init(name : String) {
                self.name = name
            }
        }
        
        class Student: PerSon {
            required init(name:String) {
                super.init(name: name)
            }
        }
    

    extension

    在swift中,extension与Objective-C的category有点类似,但是extension比起category来说更加强大和灵活,它不仅可以扩展某种类型或结构体的方法,同时它还可以与protocol等结合使用,编写出更加灵活和强大的代码。它可以为特定的class, strut, enum或者protocol添加新的特性。当你没有权限对源代码进行改造的时候,此时可以通过extension来对类型进行扩展。extension有点类似于OC的类别 -- category,但稍微不同的是category有名字,而extension没有名字。在Swift 中的可以扩展以下几个:

    (1)定义实例方法和类型方法

    (2)添加计算型属性和计算静态属性

    (3)定义下标

    (4)提供新的构造器

    (5)定义和使用新的嵌套类型

    (6)使一个已有类型符合某个接口

    //    添加计算属性
    extension Double {
        var km: Double { return self * 1_000.0 }
        var m: Double { return self }
        var cm: Double { return self / 100.0 }
    }
    class Person {
        var name:String
        var age:Int = 0
        init?(name:String) {
            if name.isEmpty {
                return nil
            }
            self.name = name
        }
        
    }
    
    extension Person {
        //添加方法
        func run() {
            print("走了50公里")
        }
    }
    
    
     let oneInch = 25.4.km
            print("One inch is \(oneInch) meters")
            /**
             
             输出结果:One inch is 25400.0 meters
             */
            
            let person = Person.init(name: "xiaom")
            person?.run()
            /**
             
             输出结果:走了50公里
             */
    

    convenient

    swift中,使用convenience修饰的构造函数叫做便利构造函数 。便利构造函数通常用在对系统的类进行构造函数的扩充时使用。便利构造函数有如下几个特点:

    (1)便利构造函数通常都是写在extension里面

    (2)便利函数init前面需要加载convenience

    (3)在便利构造函数中需要明确的调用self.init()

    extension UIButton{
        //swit中类方法是以class开头的方法,类似于oc中+开头的方法
        class func createButton(imageName:String)->UIButton{
            
            let btn=UIButton()
            btn.setImage(UIImage(named:imageName), for: .normal)
            btn.sizeToFit()
            
            return btn
        }
        /*
         convenience:便利,使用convenience修饰的构造函数叫做便利构造函数
         便利构造函数通常用在对系统的类进行构造函数的扩充时使用。
         
         */
        
        convenience init(imageName:String,bgImageName:String){
            self.init()
            if !imageName.isEmpty {
                setImage(UIImage(named:imageName), for: .normal)
            }
            if !imageName.isEmpty {
                setBackgroundImage(UIImage(named:bgImageName), for: .normal)
            }
            sizeToFit()
        }
    }
    
    
    let btn = UIButton.init(imageName: "huanying", bgImageName: "")
            btn.frame = CGRect.init(x: 10, y: 120, width: 100, height: 30)
            btn.backgroundColor = UIColor.red
            self.view.addSubview(btn)
    

    deinit

    在Swift中,deinit属于析构函数,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。和OC中的dealloc 一样的,通常在deinit和dealloc中需要执行的操作有:

    (1)对象销毁

    (2)KVO移除

    (3)移除通知

    (4)NSTimer销毁

    fallthrough

    swift语言特性switch语句的break可以忽略不写,满足条件时直接跳出循环.fallthrough的作用就是执行完当前case,继续执行下面的case.类似于其它语言中省去break里,会继续往后一个case跑,直到碰到break或default才完成的效果。

    Private FilePrivate Public Open的作用和区别

    https://blog.csdn.net/Mazy_ma/article/details/70135990

    private 修饰符

    只允许在当前类中调用,不包括 Extension
    private 现在变为了真正的私有访问控制
    用 private 修饰的方法不可以被代码域之外的地方访问

    fileprivate 修饰符

    fileprivate 其实就是过去的 private。
    其修饰的属性或者方法只能在当前的 Swift 源文件里可以访问。
    即在同一个文件中,所有的 fileprivate 方法属性都是可以访问到的。

    class A {
        fileprivate func test(){
            print("this is fileprivate func!")
        }
    }
    
    class B:A {
        func show(){
            test()
        }
    }
    

    public 修饰符

    修饰的属性或者方法可以在其他作用域被访问
    但不能在重载 override 中被访问
    也不能在继承方法中的 Extension 中被访问

    open

    open 其实就是过去的 public,过去 public 有两个作用:

    • 修饰的属性或者方法可以在其他作用域被访问
    • 修饰的属性或者方法可以在其他作用域被继承或重载 override


      20170411214159420.png

    internal

    在Swift中,public表示内部的访问权限。即有着internal访问权限的属性和方法说明在模块内部可以访问,超出模块内部就不可被访问了。在Swift中默认就是internal的访问权限。

    从高到低排序如下:

    open > public > interal > fileprivate > private

    guard

    guard 是一个新的条件声明,表示如果条件不满足时退出当前 block。任何被声明成 guard 的 optional 绑定在其他函数或 block 中都是可用的,并强制在 else 中用 return 来退出函数、continue 或 break 退出循环,或者用一个类似 fatalError() 的 @noreturn 函数来退出,以离开当前的上下文:

    defer(推迟)

    • defer的block,总是在当前方法执行后才会执行,一般会在block里面写释放资源代码。
    postfix func ++(inout x: Int) -> Int {
        defer { x += 1 }
        return x
    }
    

    try? :告诉系统可能有错, 也可能没错, 如果发生错误, 那么返回nil, 如果没有发生错误, 会见数据包装成一个可选类型的值返回给我们

    try! : 告诉系统一定没错, 如果发生错误, 程序会崩溃. 不推荐使用

    inout

    一般参数仅仅是在函数内可以改变的,当这个函数执行完后变量就会被销毁,不会有机会改变函数以外的变量,inout可以修改外部参数。

    声明函数时,在参数前面用inout修饰,在函数内部实现改变外部参数,注意,这里只能传入变量,不能传入常量和字面量,因为这些是不能变的一旦定义,当我们传入的时候,在变量名字前面用&符号修饰表示,传递给inout参数,表明这个变量在参数内部是可以被改变的

    注意:inout修饰的参数是不能有默认值的,有范围的参数集合也不能被修饰,另外,一个参数一旦被inout修饰,就不能再被var和let修饰了

    dynamic 的作用

    由于 swift 是一个静态语言, 所以没有 Objective-C 中的消息发送这些动态机制, dynamic 的作用就是让 swift 代码也能有 Objective-C 中的动态机制, 常用的地方就是 KVO 了, 如果要监控一个属性, 则必须要标记为 dynamic, 可以参考文章http://www.jianshu.com/p/ae26100b9edf

    什么时候使用 @objc

    @objc 用途是为了在 Objective-C 和 Swift 混编的时候, 能够正常调用 Swift 代码. 可以用于修饰类, 协议, 方法, 属性.
    常用的地方是在定义 delegate 协议中, 会将协议中的部分方法声明为可选方法, 需要用到@objc

    ?? 的作用

    可选值的默认值, 当可选值为nil 的时候, 会返回后面的值. 如
    let someValue = optional1 ?? 0

    相关文章

      网友评论

          本文标题:Swift笔记

          本文链接:https://www.haomeiwen.com/subject/ukpgyqtx.html