zoukankan      html  css  js  c++  java
  • 望其项背 iOS

    项目地址 https://github.com/webabcd/IosDemo
    作者 webabcd

    望其项背 iOS - swift: 其他:通过 some 修饰不透明类型(opaque type),大 Self 和小 self,inout 参数的访问冲突问题,引用计数器,强引用,weak 弱引用,unowned 弱引用,实例之间的互相强引用导致的无法释放的问题,属性闭包引用了 self 导致的循环引用问题

    示例如下:

    SwiftView15.swift

    /*
     * 本例用于演示其他
     * 通过 some 修饰不透明类型(opaque type),大 Self 和小 self,inout 参数的访问冲突问题,引用计数器,强引用,weak 弱引用,unowned 弱引用,实例之间的互相强引用导致的无法释放的问题,属性闭包引用了 self 导致的循环引用问题
     */
    
    import SwiftUI
    
    struct SwiftView15: View {
        
        var result: String = ""
        
        init() {
            result = sample1() // 通过 some 修饰不透明类型(opaque type)
            result += "
    "
            result += sample2() // 大 Self 和小 self
            result += "
    "
            result += sample3() // inout 参数的访问冲突问题
            result += "
    "
            result += sample4() // 引用计数器,强引用,weak 弱引用,unowned 弱引用
            result += "
    "
            result += sample5() // 实例之间的互相强引用导致的无法释放的问题
            result += "
    "
            result += sample6() // 属性闭包引用了 self 导致的循环引用问题
        }
    
        var body: some View {
            VStack {
                HStack {
                    Text(result)
                    Spacer()
                }
                Spacer()
            }
        }
        
        func sample1() -> String {
            let a = swiftView15_func1().name
            
            return "(a)"
        }
    
        func sample2() -> String {
            let a = SwiftView15_Struct2().getSelf().name
            
            return "(a)"
        }
        
        func sample3() -> String {
            // 下面这句会导致访问冲突,会运行时报错 Simultaneous accesses to 0x106bc01d8, but modification requires exclusive access.
            // let a = swiftView15_func2(number: &swiftView15_var1)
            
            return ""
        }
        
        func sample4() -> String {
            var a: SwiftView15_MyClass? = SwiftView15_MyClass(name: "strong") // a 被 sample4() 强引用了,此时 a 的引用计数器是 1
            var b = a // a 被 b 强引用了,此时 a 的引用计数器是 2,b 被 sample4() 强引用了,此时 b 的引用计数器是 1
            a = nil // a 变为 nil,但是 b 不是 nil,此时 a 的引用计数器是 1
            // 此时 a 没有被释放,而是要等到 sample4() 执行完后,b 的引用计数器就变为 0 了,然后 a 的引用计数器也变为 0 了,然后 a 就会被释放了
            
            weak var c: SwiftView15_MyClass? = SwiftView15_MyClass(name: "weak") // 因为 c 是 weak 弱引用,所以 c 被 sample4() 弱引用了,此时 c 的引用计数器是 0
            // 此时 c 已经被释放了,因为 c 是 weak 弱引用,所以此时的 c 的值为 nil
    
            unowned var d: SwiftView15_MyClass? = SwiftView15_MyClass(name: "unowned") // 因为 d 是 unowned 弱引用,所以 d 被 sample4() 弱引用了,此时 d 的引用计数器是 0
            // 此时 d 已经被释放了,因为 d 是 unowned 弱引用,所以如果你此时获取 d 的值的话,将会运行时报错 Fatal error: Attempted to read an unowned reference
            
            // 由上可知,weak 和 unowned 都是弱引用,他们的区别就是释放后,你获取 weak 对象的值会得到 nil,你获取 unowned 对象的值会收到运行时异常
            
            return "(b), (c)"
        }
    
        func sample5() -> String {
            let class1_1: SwiftView15_Class1? = SwiftView15_Class1(name: "strong")
            let class2_1: SwiftView15_Class2? = SwiftView15_Class2(name: "strong")
            class1_1!.class2 = class2_1
            class2_1!.class1 = class1_1
            // 上例 class1_1 对象和 class2_1 对象互相强引用了,他们永远都不会被释放,除非把 app 杀了
            
            
            let class1_2: SwiftView15_Class1? = SwiftView15_Class1(name: "weak")
            let class2_2: SwiftView15_Class2? = SwiftView15_Class2(name: "weak")
            class1_2!.class2 = class2_2
            class2_2!.class1_weak = class1_2
            // 上例 class1_2 和 class2_2 会在 sample5() 执行完后被释放,关于引用计数器,以及 weak 和 unowned 的详细说明请参见 sample4() 中的示例
            
            
            let class1_3: SwiftView15_Class1? = SwiftView15_Class1(name: "unowned")
            let class2_3: SwiftView15_Class2? = SwiftView15_Class2(name: "unowned")
            class1_3!.class2 = class2_3
            class2_3!.class1_unowned = class1_3
            // 上例 class1_3 和 class2_3 会在 sample5() 执行完后被释放,关于引用计数器,以及 weak 和 unowned 的详细说明请参见 sample4() 中的示例
            
            
            return ""
        }
        
        func sample6() -> String {
            let a = SwiftView15_Class3(name: "closure_strong")
            let b = SwiftView15_Class3(name: "closure_weak")
            
            let c = a.getMessage() // 对象 a 无法释放
            let d = b.getMessage_unowned() // 对象 b 会在 sample6() 执行完后被释放
            
            return "(c), (d)"
        }
    }
    
    
    // 用于演示不透明类型(opaque type)
    protocol SwiftView15_Protocol1 {
        associatedtype MyType
        var name: MyType { get set }
    }
    struct SwiftView15_Struct1: SwiftView15_Protocol1 {
        typealias MyType = String
        var name: MyType = "webabcd"
    }
    // 一般情况通过 -> protocol 定义返回类型是没问题的
    // 但是这里的 SwiftView15_Protocol1 协议中定义了关联类型,也就是说无法确认真实的返回类型
    // 所以这里如果通过 -> SwiftView15_Protocol1 定义返回类型的话,会编译时报错 Protocol 'SwiftView15_Protocol1' can only be used as a generic constraint because it has Self or associated type requirements
    // 于是为了解决这个问题,就引入了不透明类型,即将返回类型定义为 -> some SwiftView15_Protocol1 就好了
    func swiftView15_func1() -> some SwiftView15_Protocol1 { // 通过 some 修饰不透明类型
        return SwiftView15_Struct1()
    }
    
    
    // 用于演示大 Self 和小 self
    protocol SwiftView15_Protocol2 {
        var name: String { get set }
        func getSelf() -> Self // 这里的大 Self 指的是实现此协议的类型
    }
    struct SwiftView15_Struct2: SwiftView15_Protocol2 {
        var name: String = "webabcd"
        func getSelf() -> SwiftView15_Struct2 {
            return self // 这里的小 self 指的是当前的类实例
        }
    }
    
    
    // 用于演示 inout 参数的访问冲突
    var swiftView15_var1 = 0
    // 调用下面的方法时,如果传参是 &swiftView15_var1 就会导致访问冲突
    // 因为 number 和 swiftView15_var1 引用的是相同的内存,且 swiftView15_var1 需要读,number 需要写,也就是说在同一内存中要同时读写,这样就产生了冲突
    func swiftView15_func2(number: inout Int) {
        number = swiftView15_var1
    }
    
    
    // 用于演示强引用,weak 弱引用,unowned 弱引用
    // 在 swift 中也是通过自动引用计数器(ARC)来管理内存的,也就是说如果对象的被强引用的计数为 0 时就会被释放
    class SwiftView15_MyClass {
        var name: String
        init(name: String) {
            self.name = name
            print("(self.name) SwiftView15_MyClass init")
        }
        deinit {
            print("(self.name) SwiftView15_MyClass deinit")
        }
    }
    
    
    // 用于演示类实例之间的互相强引用,互相强引用会导致无法释放
    // 通过 weak 引用和 unowned 引用解决无法释放的问题
    // 注:struct 是值类型,所以没有办法做到下面这样
    class SwiftView15_Class1 {
        var name: String
        init(name: String) {
            self.name = name
        }
        deinit {
            print("(self.name) SwiftView15_Class1 deinit")
        }
        var class2: SwiftView15_Class2? // class2 被 class1 强引用了
    }
    class SwiftView15_Class2 {
        var name: String
        init(name: String) {
            self.name = name
        }
        deinit {
            print("(self.name) SwiftView15_Class2 deinit")
        }
        var class1: SwiftView15_Class1? // class1 被 class2 强引用了
        weak var class1_weak: SwiftView15_Class1? // class1 被 class2 通过 weak 弱引用了
        unowned var class1_unowned: SwiftView15_Class1? // class1 被 class2 通过 unowned 弱引用了
    }
    
    
    // 用于演示属性闭包的循环引用,循环引用会导致无法释放
    // 通过捕获列表并结合 weak 引用和 unowned 引用解决无法释放的问题
    class SwiftView15_Class3 {
        var name: String
        init(name: String) {
            self.name = name
        }
        
        // 注:如果要在属性的闭包中使用 self 则需要将属性标记为 lazy 属性
        // 如果在属性的闭包中引用了 self,就会导致实例持有闭包,闭包持有实例的循环应用,就会导致实例无法释放
        lazy var getMessage: () -> String = {
            return self.name
        }
        
        lazy var getMessage_unowned: () -> String = {
            // 怎么解决属性闭包引用了 self 导致的循环引用问题呢,像如下方式弱引用 self 并将其添加进捕获列表即可
            [unowned self] in
            
            // 可以类似如下这样,弱引用 self 的同时将他赋值给另一个变量。另外,如果需要将多个引用加入捕获列表的话用逗号隔开即可
            // [unowned xxx = self] in
            
            return self.name
        }
    
        deinit {
            print("(self.name) SwiftView15_class3 deinit")
        }
    }
    
    

    项目地址 https://github.com/webabcd/IosDemo
    作者 webabcd

  • 相关阅读:
    android29
    android28
    android27
    android26
    Dynamics CRM2011 MspInstallAction failed when installing an Update Rollup
    Dynamics CRM Import Solution Attribute Display Name description is null or empty
    The service cannot be activated because it does not support ASP.NET compatibility
    IIS部署WCF报 无法读取配置节“protocolMapping”,因为它缺少节声明
    Unable to access the IIS metabase.You do not have sufficient privilege
    LM算法与非线性最小二乘问题
  • 原文地址:https://www.cnblogs.com/webabcd/p/ios_SwiftView15.html
Copyright © 2011-2022 走看看