Swift笔记

2019-02-25  本文已影响7人  小二郎_Ejun

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 有两个作用:

internal

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

从高到低排序如下:

open > public > interal > fileprivate > private

guard

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

defer(推迟)

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

上一篇下一篇

猜你喜欢

热点阅读