Swift编程

swift 小知识点汇总

2020-03-02  本文已影响0人  pengxiaochao

1. class 和 struct 的区别

class 为类, struct 为结构体, 类是引用类型, 结构体为值类型, 结构体不可以继承

2.map、filter、reduce 的作用

map 用于映射, 可以将一个列表转换为另一个列表

[1, 2, 3].map{"\($0)"}// 数字数组转换为字符串数组
//["1", "2", "3"]

filter 用于过滤, 可以筛选出想要的元素

[1, 2, 3].filter{$0 % 2 == 0} // 筛选偶数
//[2]

reduce 合并

[1, 2, 3].reduce(""){$0 + "\($1)"}// 转换为字符串并拼接
//"123"

3.map 与 flatmap 的区别

flatmap 有两个实现函数实现

    public func flatMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] 

这个方法, 中间的函数返回值为一个可选值, 而 flatmap 会丢掉那些返回值为 nil 的值
例如

//例如
["1", "@", "2", "3", "a"].flatMap{Int($0)}
// [1, 2, 3]
["1", "@", "2", "3", "a"].map{Int($0) ?? -1}
//[Optional(1), nil, Optional(2), Optional(3), nil]

另一个实现
public func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Iterator.Element] where SegmentOfResult : Sequence
中间的函数, 返回值为一个数组, 而这个 flapmap 返回的对象则是一个与自己元素类型相同的数组

func someFunc(_ array:[Int]) -> [Int] {
    return array
}
[[1], [2, 3], [4, 5, 6]].map(someFunc)
//[[1], [2, 3], [4, 5, 6]]
[[1], [2, 3], [4, 5, 6]].flatMap(someFunc)
//[1, 2, 3, 4, 5, 6]

其实这个实现, 相当于是在使用 map 之后, 再将各个数组拼起来一样的

[[1], [2, 3], [4, 5, 6]].map(someFunc).reduce([Int]()) {$0 + $1}
// [1, 2, 3, 4, 5, 6]

4.如何获取当前代码的函数名和行号

file 用于获取当前文件文件名

line 用于获取当前行号

column 用于获取当前列编号

function 用于获取当前函数名

var file: String = #file
var line: String = #line
var column: String = #column
var function: String = #function
method: String = #function,
print("\(file)--\(line)--\(columne)--\(function))

5.private,fileprivate,internal,public 和 open 五种访问控制的权限

//1.当private 或fileprivate 修饰属性的时候
privte 修饰的属性只能在本类的作用域且在当前文件内能访问
fileprivate 修饰的属性只能在当前文件内访问到,不管是否在本类作用域

//2. fileprivate 修饰方法的时候
fileprivate 修饰的方法,类的外部无法调用
fileprivate 修饰方法,子类定义的同一个文件中,可以访问
fileprivate 修饰方法,子类定义不在同一个文件,不可以访问


//3.public 和 open 的区别
这两个都用于在模块中声明需要对外界暴露的函数, 区别在于, public 修饰的类, 在模块外无法继承, 而 open 则可以任意继承, 公开度来说, public < open

6. guard 的使用场景

swift 的语法糖之一

//当(条件) 为false 的时候进入{}
guard 条件
{
        
}

7.if let 语法糖使用场景

swift 中因为有optional,所以需要经常判空,举例说明if let 解决了什么问题

//不使用if let
func doSometing(str: String?){
    ...
}
let value :String ! = str
if value != ni {
     //如果value 不为 nil进入大括号执行
}

//使用了if let 简洁了很多
func doSometing(str: String?){
     ...
}
if let value = str {
    //如果value 不为 nil进入大括号执行
}

8.defer的使用场景

defer 语句块中的代码, 会在当前作用域结束前调用, 常用场景如异常退出后, 关闭数据库连接

func someQuery() -> ([Result], [Result]){
    //假如打开数据库失败        
    let db = DBOpen("xxx")
    defer {
        db.close()
    }
    //或者 查询失败导致异常退出 调用defer,执行里面的代码
    guard results1 = db.query("query1") else {
        return nil
    }
    guard results2 = db.query("query2") else {
        return nil
    }
    return (results1, results2)
}

9.String 与 NSString 的关系与区别

NSString 与 String 之间可以随意转换

let someString = "123"
let someNSString = NSString(string: "n123")
let strintToNSString = someString as NSString
let nsstringToString = someNSString as String

10.associatedtype 的作用

简单来说就是 protocol 使用的泛型
例如定义一个列表协议

protocol ListProtcol {
    associatedtype Element
    func push(_ element:Element)
    func pop(_ element:Element) -> Element?
}

实现协议的时候, 可以使用 typealias 指定为特定的类型, 也可以自动推断, 如

class IntList: ListProtcol {
    typealias Element = Int // 使用 typealias 指定为 Int
    var list = [Element]()
    func push(_ element: Element) {
        self.list.append(element)
    }
    func pop(_ element: Element) -> Element? {
        return self.list.popLast()
    }
}
class DoubleList: ListProtcol {
    var list = [Double]()
    func push(_ element: Double) {// 自动推断
        self.list.append(element)
    }
    func pop(_ element: Double) -> Double? {
        return self.list.popLast()
    }
}

11.关于泛型的使用

class AnyList<T>: ListProtcol {
    var list = [T]()
    func push(_ element: T) {
        self.list.append(element)
    }
    func pop(_ element: T) -> T? {
        return self.list.popLast()
    }
}

12.可以使用 where 字句限定 Element 类型, 如:

extension ListProtcol where Element == Int {
    func isInt() ->Bool {
        return true
    }
}

13. ?? 的用法

可选值的默认值, 当可选值为nil 的时候, 会返回后面的值. 如

let someValue = optional1 ?? 0

14. lazy 的用法

swift 中的懒加载,只有被调用到的时候,才初始化和赋值

class LazyClass {
    lazy var someLazyValue: Int = {
        print("lazy init value")
        return 1
    }()
    var someNormalValue: Int = {
        print("normal init value")
        return 2
    }()
}
let lazyInstance = LazyClass()
print(lazyInstance.someNormalValue)
print(lazyInstance.someLazyValue)

15.swift block循环引用解决

在其参数前面使用[weak self]或者[unowned self]

let emtyOb = Observable<String>.empty()
_ = emtyOb.subscribe(onNext: { [weak self] (number) in
    
    print("订阅:",number)
    self.label.text = number
})

16. dynamic 的用法

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

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

@objc protocol OptionalProtocol {
    @objc optional func optionalFunc()
    func normalFunc()
}
class OptionProtocolClass: OptionalProtocol {
    func normalFunc() {
    }
}
let someOptionalDelegate: OptionalProtocol = OptionProtocolClass()
someOptionalDelegate.optionalFunc?()

17. 什么是高阶函数

一个函数如果可以以某一个函数作为参数, 或者是返回值, 那么这个函数就称之为高阶函数, 如 map, reduce, filter

18. static 和 class 有什么区别

static 定义的方法不可以被子类继承, class 则可以

class AnotherClass {
    static func staticMethod(){}
    class func classMethod(){}
}
class ChildOfAnotherClass: AnotherClass {
    override class func classMethod(){}
    //override static func staticMethod(){}// error
}

19.枚举定义

与OC不一样,Swift的枚举扩展性很强了,OC只能玩Int,swift 支持

整型(Integer)
浮点数(Float Point)
字符串(String)
布尔类型(Boolean)

enum Movement {
    case letf
    case right
    case top
    case bottom
}
enum Area: String {
    case Dong = "dong"
    case Nan = "nan"
    case Xi = "xi"
    case Bei = "bei"
}

//嵌套枚举
enum Area {
    enum DongGuan {
        case NanCheng
        case DongCheng
    }
    
    enum GuangZhou {
        case TianHe
        case CheBei
    }
}

//枚举关联值
enum Trade {
    case Buy(stock:String,amount:Int)
    case Sell(stock:String,amount:Int)
}

let trade = Trade.Buy(stock: "003100", amount: 100)

switch trade {
case .Buy(let stock,let amount):
    
    print("stock:\(stock),amount:\(amount)")
    
case .Sell(let stock,let amount):
    print("stock:\(stock),amount:\(amount)")
default:
    ()
}

20. swift中set 、get 方法

swift 中的set 和 get 要复杂一点。 在swift 中主要分存储型属性计算型属性 这两种 , 一般 我们只是给计算属性添加 get\set 重写

var command:Int {
    get {
        //return command; 会导致死循环
        //return self.command; 会导致死循环
        //return _command; 会导致死循环
        //且不能像OC那样 return _command;
        return 1
    }
    set {
        //新值 newValue
        //value 为一个外部属性变量
        value = newValue
    }
}

//为了解决储型属性的set、get 方法问题
var _command:int?
var command :Int {
    get {
       return _command 
    }
    set {
       _command = newValue 
    }
}

21. swift 中 willset 和didset 方法

属性初始化的时候,willSet 和didSet 不会调用,只有在初始化上下文之外,属性发生改变的时候调用;
给属性添加观察者属性的时候,必须声明属性类型,否则编译会报错;

var command :Int {
    willSet {
       print("newValue is \(newValue)")
    }
    didSet {
      print("newValue is \(newValue)")
      print("oldValue is \(oldValue)")
    }
}
上一篇下一篇

猜你喜欢

热点阅读