美文网首页
swift 进阶知识点

swift 进阶知识点

作者: 小小小蚍蜉 | 来源:发表于2019-10-11 15:23 被阅读0次

    1、git本地仓库分:工作区,版本区(暂存区+仓库区);
    git add . 即是将工作区修改的代码提交到暂存区,在通过git commit *** 将暂存区的代码提交到仓库区。
    git reset 即是将仓库区的代码恢复到暂存区,通过git checkout 恢复某版本

    2、git merge --no-ff *** 禁用Fast-forward模式,因为开启Fast-forward模式,删除分支后,历史信息会丢失。

    3、Enum枚举item想要使用引用语义时,需要在对应case项前加关键字indirect。

    4、swift提供有序数组DictionaryLiteral<Key, Value>(注释:5.0以后废弃) = KeyValuePairs<Key, Value>(注释:5.0以后使用)

    5、flatMap在4.1后废弃,苹果推荐使用compactMap。二者使用原理有对以下方法使用的区别:

      //  直接添加Any对象
      [].append(<#T##newElement: Any##Any#>)
     // 添加遵守Sequence协议的element元素
      [].append(contentsOf: <#T##Sequence#>)
    
    @available(swift, deprecated: 4.1, renamed: "compactMap(_:)", message: "Please use compactMap(_:) for the case where closure returns an optional value")
        public func flatMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
    

    6、mutating关键字可以将隐式的self参数变为可变的,假如mutating标记结构体的方法,则方法中隐式的self被标记为了inout。

    7、高性能的写时复制:swift中使用了isKnownUniquelyReferenced函数来检查某个引用是否只有一个持有者。如果你将一个swift类实例传递给这个函数,并且没有其他变量强引用这个对象,函数将返回true。否则返回false。而对于Objectiive-C并不会返回false。

    8、对每个 unowned 的引用,Swift 运行时将为这个对象维护另外一个引用计数。当所有的 strong 引用消失时,对象将把它的资源 (比如对其他对象的引用) 释放掉。不过,这个对象本身的内存 将继续存在,直到所有的 unowned 引用也都消失。这部分内存将被标记为无效 (有时候我们也 把它叫做僵尸 (zombie) 内存),当我们试图访问这样的 unowned 引用时,就会发生运行时错误。
    不过注意这其实并不是未定义的行为。我们还有第三种选择,那就是 unowned(unsafe),它不 会做运行时的检查。当我们访问一个已经无效的 unowned(unsafe) 引用时,这时候结果将是未 定义的。

    9、Codable协议的使用,JSONEncoder().encoder(参数)和JSONEncoder().decode([类],from: (Data参数))

    struct Coordinate: Codable {
        var latitude: Double
        var longitude: Double
    }
    
    struct PlaceMark: Codable {
    
        var name: String
        var coordinate: Coordinate
    
        private enum CodingKeys: CodingKey {
    
            case name
            case coordinate
        }
    
    
        func  encode(to encoder: Encoder) throws {
    
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(name, forKey: .name)
            try container.encode(coordinate, forKey: .coordinate)
        }
    }
    
    let places: [PlaceMark] = [PlaceMark(name: "Berlin", coordinate: Coordinate(latitude: 52, longitude: 13)),
                  PlaceMark(name: "Cape Town", coordinate: Coordinate(latitude: -34, longitude: 18))
        ]
    
    do {
        let encoder = JSONEncoder()
        let jsonData = try encoder.encode(places)
        let jsonString = String(decoding: jsonData, as: UTF8.self)
    
        let decoder = JSONDecoder()
        let decoded = try decoder.decode([PlaceMark].self, from: jsonData)
        type(of: decoded)
    } catch  {
    
    }
    

    10、inout做的事情是值传递,然后复制过来,而不是传递引用。【官网:inout参数将一个值传递给函数,函数可以改变这个值,然后将原来的值替换掉,并从函数中传出】。

    inout如果有物理内存地址,且没有属性观察器,直接将内存地址传入函数。

    如果是计算属性,或者设置了属性观察器,采取Copy-In-Copy-out做法,调用该函数,先复制实参的值,产生副本,将副本的内存地址传入函数(副本进行引用传递),在函数内部可以修改副本的值

    ps:编译器可能会把inout变量优化成引用传递,而非传入和传出的复制

    11、如果一个函数接受 UnsafeMutablePointer 作为参数,你可以用和 inout 参数类似的方法,将 一个 var 变量前面加上 & 传递给它。在这种情况下,你确实在传递引用,更确切地说,你在传 递指针。

    
    func incref(pointer: UnsafeMutablePointer<Int>) -> ()->[Int] {
          return {
            pointer.pointee += 1
            return pointer.pointee
        }
    }
    
    let fun: () -> Int do{
    var array = [0]
    fun = incref(pointer: &array) }
    fun()
    
    

    12、@_specialize非官方标签:能将你的泛型代码进行指定版本的特化,使其在其他模块中也可以使用。只在当你知道你的代码将如何被一些有限的类型使用时,能有帮助,对标记为public的函数才有效。

    
    @_specialize(exported: true, where T == Int)
    @_specialize(exported: true, where T == String) 
    public func min<T: Comparable>(_ x: T, _ y: T) -> T {
    returny<x?y:x 
    }
    
    

    另外还有一个相似 (同样非官方支持) 的 @_inlineable 标签,当构建代码时,它指导编译器将被 标记函数的函数体暴露给优化器。这样,跨模块的优化壁垒就被移除了。相比 @_specialize, @_inlineable 的优势在于,原来的模块不需要将具体类型硬编码成一个列表,因为特化会在使 用者的模块进行编译时才被施行。

    13、 全模块优化会同时启用一些其他的重要优化。比如,优化器将会识别出整个模块中没 有子类的 internal 类。因为 internal 关键字确保了这个类不会出现在模块外部,所以 这意味着编译器可以将这个类的所有方法调用从动态派发转变为静态派发。

    14、协议有两种:带有关联类型(associatedtype)的协议和普通的协议。
    定义协议时声明的方法是动态派发,协议扩展中的方法是静态派发的。

    当实例被定义为(协议)类型的变量时,编译器会自动将此实例值封装到一个代表协议的类型中,这个封装即是存在容器。
    对存在容器调用(仅仅)在协议扩展中声明实现的方法时,调用是静态派发的,如果是动态派发,需要将方法接收者类型考虑在内或者将协议扩展中的方法在协议定义中声明。

    因为是协议定义的一部分,它将被动态派发,在运行时,根据方法接收者的动态类型不同,存在容器将会在自定义实现存在是对其进行调用,如果自定义实现不存在时,那么它将使用协议扩展中默认实现的方法。(结尾附:测试代码)

    15、Swift 的结构体一般被存储在栈上,而非堆上。不过对于可变结构体,这其实是一种优化:默认 情况下结构体是存储在堆上的,但是在绝大多数时候,这个优化会生效,并将结构体存储到栈 上。编译器这么做是因为那些被逃逸闭包捕获的变量需要在栈帧之外依然存在。当编译器侦测 到结构体变量被一个函数闭合的时候,优化将不再生效,此时这个结构体将存储在堆上。

    协议测试代码:

    
    protocol Drawing {
        
        mutating func addEllipse(rect: CGRect, fill: UIColor)
        mutating func addRectangle(rect: CGRect, fill: UIColor)
    // 打开注释验证即使是声明Drawing变量,依然走此(协议遵守类)遵守的协议方法
       // mutating func addCircle(center: CGPoint, radius: CGFloat, fill: UIColor)
    }
    
    extension Drawing {
        
        mutating func addCircle() {
            print("纯协议扩展")
        }
    }
    
    extension CGContext: Drawing {
       
        func addEllipse(rect: CGRect, fill: UIColor) {
            
            setFillColor(fill.cgColor)
            fillEllipse(in: rect)
        }
        
        func addRectangle(rect: CGRect, fill: UIColor) {
            setFillColor(fill.cgColor)
        }
        
    }
    
    struct SVG {}
    
    extension SVG: Drawing {
        
        func addRectangle(rect: CGRect, fill: UIColor) {
            print("结构体----扩展---遵守协议--内---addRectangle")
        }
        
        func addEllipse(rect: CGRect, fill: UIColor) {
            print("结构体----扩展---遵守协议--内---addEllipse")
        }
    }
    
    extension SVG {
        
        mutating func addCircle() {
            print("结构体----扩展---遵守协议---后")
        }
    }
    
    var smaple = SVG()
    smaple.addCircle()
    print(smaple)
    
    var otherSample: Drawing = SVG()
    otherSample.addCircle()
    print(otherSample)
    
    

    相关文章

      网友评论

          本文标题:swift 进阶知识点

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