Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Swift Reference Cycle中的weak,unowned,Closure Capture List

Swift Reference Cycle中的weak,unowned,Closure Capture List

作者头像
iOS Development
发布于 2019-02-14 09:44:12
发布于 2019-02-14 09:44:12
1K00
代码可运行
举报
运行总次数:0
代码可运行

截图Xcode版本:Xcode 10.1

如果您在用SwiftiOS开发,且暂时不是很清楚什么时候用weak、什么时候用unowned、或者不是很清楚什么是closure capture list,那么,此文尚值一读。

TL;DR(太长不看版)

  • weak还是用unowned,和对象的lifetime(生命周期)有关;
  • 如果两个对象的生命周期完全和对方没关系(其中一方什么时候赋值为nil,对对方都没影响),请用weak(来解决Reference Cycle);
  • 如果你有十足信心确保:其中一个对象销毁,另一个对象也要跟着销毁,这时候,可以(谨慎)用unowned(来解决Reference Cycle);
  • closure capture list,是在closures(闭包)内,把capture(捕抓)到的对象、值,放到一个方括号中的语法。在方括号(capture list)中,可以利用weak、unowned关键字把默认的strong reference 改为非strong reference,从而解决closures和类实例(class instance)之间的Reference Cycle;
  • Xcode 8 推出的工具Debug Memory Graph可以在App运行时十分方便定位到产生Reference Cycle的代码。

ARC定义

上面的关键字,都和Swift的内存管理机制ARC(Automatic Reference Counting/自动引用计数 )有关,而且都是在解决Reference Cycle(引用循环)需要用到的关键字。

Swift的官方文档Automatic Reference Counting中并没有对ARC进行定义,但是可以参考Objective-C中关于ARC的定义,因为Objective-C中的ARC和Swift的非常相似(very similar)。

Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects.

从定义可知,ARC是编译器提供的一个特性,用于自动管理内存。

结论就是:在大部分情况下,开发者无需操心内存管理的事情:

In most cases, this means that memory management “just works” in Swift, and you do not need to think about memory management yourself.

不过,剩下的这「小部分」情况,也够大家头大的……

这「小部分」情况是什么呢,就是Reference Cycle。

用weak解决Reference Cycle

Reference Cycle是什么

什么是Reference Cycle、Reference Cycle有什么危害?

因为官方文档举例用了Person和Apartment两个classes,所以这里举个可能不太恰当的例子:

想象一下,房地产商在北京建了一套房子Apartment,然后出租给一个租客Tenant。突然某天,晴天一个霹雳,租客意外挂了,同时房地产商又接了P2P暴雷的接力棒——也暴了。这时候,你把这个Apartment想象成电脑中的一块内存,因为知道这个Apartment存在的两方都被导演安排去领饭盒了,这个Apartment就白白浪费在城市中了,如果陆续出现很多这种情况,这个城市很多房产就浪费掉了——好比如电脑中的内存被浪费掉。

上面的情况,可以把它简单理解为Reference Cycle,它会导致内存浪费——内存浪费到一定程度,你的程序可能会crash,所以要避免。下面用官方文档的图示进一步阐述:

image

▲1. 左边是我们潜在租客(Tenant)john,右边是我们房地产商新建的一个Apartment,起了个很洋气的名字unit4A。可以看到,john还没租到房子——apartment属性为nil;房子unit4A也还没找到租客——tenant属性为nil,大家各不相干。

image

▲2. 第二张图可以看到,apartment属性和tenant属性都有值了,而且中间多了两个strong的箭头,表示他们的关系。可以把它们理解成租客和房东签订了合同,确立了租赁关系(但是这个「合同」是有问题的,会导致Reference Cycle)。

image

▲3. 第三张图,我们看到,租客和房地产商都被导演安排去领饭盒了——都被赋值了nil(上面的两个strong箭头不见了)。不过因为他们之前签的合同没有第三方知道,所以大家都以为这个房子还在住人,导致房子没有流回租赁市场,造成浪费。

以上用了一个不太恰当的比喻描述Reference Cycle。

而在Xcode的debug工具Debug Memory Graph,则是用图片这样描绘的:

image

感觉挺形象的(后面会说明Debug Memory Graph的简单用法)

weak 关键字

那怎么解决呢?用weak这个关键字,继续看图示:

image

▲4. 这张图和图2有个小区别,就是下面的strong箭头变成成了灰色的weak。打个比方,他们重新签订合同,规定租客两个月不交租的话,就失去房子的租赁权,要被回收、再出租。

image

▲5 . 一语中的,租客john真的狗带了(被赋值为nil),同时他对Apartment的strong reference也随之消失。而Apartment指向Person实例的是weak reference,不持有Person实例,所以 tenant重设为nil。房子可以重新出租给其他人。但是,如果这时候房地产商也暴雷倒闭了,就出现以下情况:

image

▲6 .房子现在成为无主孤魂了——房地产商不持有,租客也不持有。所以超级管理员——政府就知道可以回收再利用了。

上面举例说明了类实例之间的Reference Cycle和其「解决」方法——用weak关键字修饰属性,下面看官方文档的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 这种写法,会引起Reference Cycle,因为大家都是strong reference,互相持有对方,最后得不到释放。
class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

// 修正:Apartment改为这种写法,即可解决Reference Cycle
class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    // 具体就是改了这里,tenant属性,用weak关键字修饰 
    weak var tenant: Person? // 因为tenant有可能会是nil,所以是Optional Type,可以理解为,房子不一定有租客。(weak修饰的,一定是Optional Type)
    deinit { print("Apartment \(unit) is being deinitialized") }
}

用unowned解决Reference Cycle

再举个不恰当的例子:

想象一下,我们有「Customer/客户」和「CreditCard/信用卡」两个类。这种情况和「租客」和「房子」的不同点在于,「租客」和「房子」都可以作为独立的存在,它们的lifetime(生命周期)没有跟对方没有直接的因果关系。而「客户」和「信用卡」的关系则不同:「客户」可以单独存在,「信用卡」不行。「信用卡」被创造出来的前提是——肯定先有「客户」(联想一下现实生活:银行都是在用户申请信用卡之后才制卡的,不可能预先制造一堆卡——因为卡上要印「客户」的名字)。所以,「客户」的lifetime(生命周期)一定是和「信用卡」一样、或者更长的。

怎么表达这种关系呢?Swift中用的是unowned关键字:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Customer {
    let name: String
    var card: CreditCard? // 「客户」不一定有「信用卡」,所以这里是Optional Type
    init(name: String) {
        self.name = name
    }
    deinit { print("\(name) is being deinitialized") }
}

class CreditCard {
    let number: UInt64 
    // 这里用unowned,因为「客户/Customer」和「信用卡」的lifetime一样,或者比「信用卡」更长
    unowned let customer: Customer // 有「信用卡」,就一定有「客户」,所以这里不能用Optional Type(nonoptional)
    // 有「客户」才能创建「信用卡」,所以init方法,要传Customer参数
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("Card #\(number) is being deinitialized") }
}

这时候的图示如下:

image

▲7 .比起上面「租客」和「房子」的关系,右边「信用卡」这个instance,少了一个strong refrence指向它。

之所以叫unowned,可能是因为「Customer」可以拥有(own)「CreditCard」,但是「CreditCard」不能拥有(does not own )「Customer」(或者是:除了指定「Customer」这个owner外,不可以有其他owner,Who knows?)。

小结weak和unowned

个人总结两者的异同:

  • 相同点 weakunowned都可以解决Reference Cycle,所以他们相同的地方:
    • 都不会对object进行reference count(引用计数)加1的操作
    • 都可以解决reference cycle这个问题(这句好像有点废)
  • 不同点
    • weak修饰的属性,只能是变量(var),同时只能是Optional类型,因为在模拟实际情境中,这个属性有可能是没有具体值的。换言之你需要手动检查解包后才能使用——所以朝阳群众说这样更安全;
    • unowned修饰的属性,不能是Optional类型(一定是nonoptional类型),(想象一样,银行肯定要有了「客户」之后,才能制作该「客户」的「信用卡」);
    • weak属性,初始化后也可以为nil;
    • unowned属性,初始化后一定都有值;
    • weakunowned更安全(原因见「不同点」第一条);
    • unownedweak性能好一点点(出处——倒数第二段)

下面这张插图,比较直观描绘出strong、weak、unowned在属性声明时的异同(图片来源:ARC and Memory Management in Swift):

image

那么,问题来了,我究竟什么时候用weak,什么时候用unowned?

官方文档给出的答案是:

Unlike a weak reference, however, an unowned reference is used when the other instance has the same lifetime or a longer lifetime.

对于什么时候用unownedWhen to use strong, weak and unowned reference types in Swift and why一文给出类似的答案:

The rule here is to use it if we can guarantee that the lifecycle of the referenced object is equal or greater than the lifetime of the variable pointing to it. In that case we know for sure that the object will not be deallocated and we can safely use it.

上面用对象的「lifetime/生命周期」来解释,相对抽象,感觉也不好判断,在具体实践中或许可以这样判断:

  • 当两个属性在实际情况中都允许是nil的时候(「Person」中的「apartment」,「Apartment」中的「tenant」,初始化后,都可以为nil):用weak;
  • 当一个属性允许是nil(「Customer」中的属性「card」),另一个属性不允许是nil(「CreditCard」中的「customer」,「CreditCard」初始化成功后,属性customer一定要有值):就用unowned。

什么?你现在还像我一样黑人问号?那可以简单点:当你不知道用weak还是用unowned的时候,用weak吧。为什么?因为群众说weak更安全——毕竟安全第一。

补充:用unowened + Implicitly Unwrapped Optional解决Reference Cycle

上面说了两种情况:

  • 两个属性同时允许是nil;
  • 一个属性允许是nil,另一个不允许是nil。

官方文档还描述了第三种情况:两个属性都不允许是nil——初始化完成后,一定都要有值。(官方文档举例:「Country/国家」一定会有「capitalCity/首都」,「capitalCity」也一定会有它所在的「Country」)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Country {
    let name: String
    var capitalCity: City! // 用Implicitly Unwrapped Optional的方式(就是加个感叹号),表示初始化后属性一定有值,不为nil(备注:还是Optional类型,初始化前的默认值也是nil)
    init(name: String, capitalName: String) {
        self.name = name
        // 其实到这里为止,就算是初始化完成了,因为name赋值了,capitalCity也有默认值nil。所以下面这句不写也不会报错。另外,因为初始化完成,所以可以调用selfe了
        // 下面这句,是为了满足实际初始化需求:初始化结束后,capitalCity一定有值
        self.capitalCity = City(name: capitalName, country: self)
    }
}

class City {
    let name: String
    // 这里和上面的unowned用法一致
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

// 这样一句代码,就可以创建两个实例了(而且他两的lifetime都一样:同时创建、同时销毁——所以可以用unowned)
var country = Country(name: "Canada", capitalName: "Ottawa")
print("\(country.name)'s capital city is called \(country.capitalCity.name)")

上述情况,就是用unowenedImplicitly Unwrapped Optional解决Reference Cycle。

Implicitly Unwrapped Optional就是在声明capitalCity这个Optional属性时,加上叹号,用来表示初始化后一定有值(「国家」建立了,就一定要有「首都」啊),并且后面也可以不解包直接访问。

用capture list解决Reference Cycle

Closures(闭包)和class instance(类实例)之间,也有可能产生Reference Cycle,这种情况用capture list解决。

在讲Closures中的Reference Cycle前,先明确以下几点:

  • Closures是Reference Type——所以才有可能产生Reference Cycle
  • 在Closures内,使用Closures外的常量、变量,这种行为被定义为「capture」,有以下几种语法表现: // 如果什么都不写,直接使用。默认是strong类型的capture(想象一下,这时候就有一个粗粗的箭头指向self) // 下面这句,意思就是把title实例capture到closure里来用(为什么强制写self,下面解释) myFunction { print(self.title) } // implicit strong capture // 把capture的对象放在方括号,是显式地声明capture行为,也是strong类型的capture myFunction { [self] in print(self.title) } // explicit strong capture // 显式地声明capture回来的实例,是weak类型的reference // 因为weak reference只能是optional类型,所以使用时要解包处理(感叹号强制解包) myFunction { [weak self] in print(self!.title) } // weak capture // 显式地声明capture回来的实例是unowned类型的reference myFunction { [unowned self] in print(self.title) } // unowned capture
    • 上面closures的第一种写法,在closure内,使用外面的title,Swift强制要加上self,否则编译报错。原因是为了提醒用户,这里「capture」了self的实例,有可能会造成Reference Cycle,要多加注意。
    • 方括号内,可以放多个值;
    • Closures内方括号放若干个值,这种语法,叫做「Capture List」;
    • 如果显式地把「Capture List」写出来,就一定要和in关键字搭配使用——即使Closures中没有参数、没有返回值;
    • 对于Value Type,显式地用方括号capture回来的值,会copy一份到closures里面(是不能修改的let常量),这时候和原来外面的值就没关系了;如果不是写在「Capture List」里,closures内外就共享一个值;
    • 而对于Reference Type,无论是否显式地写「Capture List」,指向的都是同一个Reference;「Capture List」的作用,是用于声明是weak,还是unowned类型的Reference。
    • Closures、classes实例之间的Reference Cycle,就是用这种方法(Capture List)来解决的。

先看看Closures、classes实例之间的Reference Cycle长啥样:

image

▲ 这是官方文档的示意图。可以看到,实例化一个HTMLElement对象后:asHTML属性指向closure,而closure因为capture了self,也指向HTMLElement对象(self),最后造成Reference Cycle。

image

再看看Xcode中Debug Memory Graph描绘出来的图示,也很形象,有一个箭头,跑了一圈,又回到了HTMLElement对象自身。

而在代码中,表现是这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class HTMLElement {
    
    let name: String
    let text: String?

    lazy var asHTML: () -> String = {
        // 如果没有写capture list(方括号内加若干属性),默认是strong reference的。
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) is being deinitialized")
    }
}

// 这时候只要创建HTMLElement实例,就会Reference Cycle
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
paragraph = nil // 赋值为nil,也不会调用deinit()销毁对象

而解决办法,就是上面说的Capture List

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class HTMLElement {

    let name: String
    let text: String?

    // 在closure里面,用Capture List,将默认的Strong Reference,声明为不增加Reference Count的unowned self(当然,用weak self也有一样的效果,下面说明具体区别)
    // 注意,用Capture List,后面就一定要用in
    lazy var asHTML: () -> String = {
        [unowned self] in
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) is being deinitialized")
    }
}

看上述代码,用[unowned self],把原来默认的strong reference手动改为unowned referenc,即可解决问题。

而关于用weak还是unowned,和class实例之间的Reference Cycle类似。你能确保closure和它capture回来的对象一直引用对方(初始化后一直有值,不可能为nil)、并且会同时销毁,就用unowned;如果closure capture回来对象,有可能在某一时刻会变成nil(有可能为nil),就用weak

什么?也还是不明白?那就不负责任地说一句:用weak吧~

Debug Memory Graph

Debug Memory Graph是Xcode 8开始有的一个新工具,将内存中的对象可视化。致力于回答一个问题:

Why does this object exist?

这个工具可以很方便地帮你检查出项目中可能存在的内存问题,也是检查是否有Reference Cycle的神器,具体应用可看如下图示:

image

WWDC2016: Visual Debugging with Xcode 24:40有详细介绍Debug Memory Graph

Reference

When to use strong, weak and unowned reference types in Swift and why

strong, weak, unowned - Reference Counting in Swift

Memory Management in Swift: Understanding Strong, Weak and Unowned References

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.11.17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Swift基础 自动参考计数
翻译自:https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html
郭顺发
2023/07/17
1460
Swift 自己主动引用计数机制ARC「建议收藏」
Swift 使用自己主动引用计数(ARC)这一机制来跟踪和管理你的应用程序的内存。通常情况下,Swift 的内存管理机制会一直起着作用,你无须自己来考虑内存的管理。ARC 会在类的实例不再被使用时,自己主动释放其占用的内存。
全栈程序员站长
2022/07/10
6720
Swift 自己主动引用计数机制ARC「建议收藏」
重读swift官方文档之 weak unowned
在swift开发中强引用和循环引用很容易发生的,针对这个情况swift使用了两个关键词作为破处这种循环引用的方式:weak unowned
大话swift
2019/07/03
5830
重读swift官方文档之 weak unowned
Swift 中的内存管理详解
这篇文章是在阅读《The Swift Programming Language》Automatic Reference Counting(ARC,自动引用计数)一章时做的一些笔记,同时参考了其他的一些资料。
哲洛不闹
2018/09/18
1.6K0
Swift 中的内存管理详解
Swift3.0 - 自动引用计数(strong,weak,unowned)
定义两个类Student 和School,Student 有一个属性school ,school 也有一个属性student,我们让其相互引用
酷走天涯
2018/09/14
6130
开心档之Swift 自动引用计数(ARC)
在上面的例子中,ARC 会跟踪你所新创建的 Person 实例的引用数量,并且会在 Person 实例不再被需要时销毁它。
iOS Magician
2023/03/21
5770
Swift专题讲解十六——ARC在Swift中的应用
        ARC(自动引用计数)是Objective-C和Swift中用于解决内存管理问题的方案。在学习Objective-C编程时经常会学习到一个关于ARC的例子:在一个公用的图书馆中,每次进入一人就将卡插入,走的时候将自己的卡拔出拿走。图书馆系统会判定只要有卡插入,就将图书馆的灯打开,当所有卡都被取走后,将图书馆的灯关掉。这个例子对应于Objective-C中的对象声明周期管理十分贴切。每当一个对象增加一个引用时,其引用计数会加1,当一个引用被取消时,对象的引用计数减1,当引用计数减为0时,说明此对象将不再有任何引用,对象会被释放掉,让出内存。Swift也采用同样的方式进行内存管理。
珲少
2018/08/15
1.5K0
Swift专题讲解十六——ARC在Swift中的应用
【读书笔记】The Swift Programming Language (Swift 4.0.3)
素材:Language Guide 初次接触 Swift,建议先看下 A Swift Tour,否则思维转换会很费力,容易卡死或钻牛角尖。 同样是每一章只总结3个自己认为最重要的点。这样挺好!强迫你去思考去取舍。以后再看,也方便快速重建记忆。 注意: 个人笔记,仅供参考,不保证严格意义上的正确性。 The Basics * 整数,优先使用 Int,浮点数,优先使用 Double * 可以使用 0b 表示二进制,可以在数字中间插入可读字符 _,如 182_3880_25 * as 仅用于兼容类型间的相互转换.
ios122
2018/03/30
1.5K0
iOS 面试策略之语言工具-Swift
本章节主要针对 iOS 的主流开发语言 Objective-C 和 Swift 进行分析和对比,同时也整理了 Xcode 编辑器的使用技巧和经验。
会写bug的程序员
2021/04/27
1.4K0
iOS 面试策略之语言工具-Swift
Swift中的内存管理
之前用Swift写了一个App,已经在App Store上架了。前两天更新了一些功能,然后用Instruments检查的时候,发现有内存泄漏问题。有些同学可能觉得奇怪,Swift不是使用ARC自动管理内存的么,怎么也会发生内存泄漏呢。是会的,但几乎都是由于操作不当造成循环引用(strong reference cycle/retain cycle)导致的。
Sheepy
2018/09/10
1.7K0
Swift中的内存管理
万字长文|Swift语法全面解析|附示例
Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 应用的新语言。 swift 是一种安全,快速和互动的编程语言。 swift 支持代码预览(playgrounds),这个特性可以允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。
悟空聊架构
2020/07/30
3.8K0
Swift: 为什么要避免在结构体中使用闭包?
闭包可以简化iOS开发人员的工作。好吧,如果这使我们工作变得容易,那为什么我要避免在Swift结构中使用闭包呢? 原因是:内存泄漏和意外行为。
韦弦zhy
2020/03/20
1.8K0
Swift: 为什么要避免在结构体中使用闭包?
Swift 闭包支持隐式 self
在 closure 捕获列表中,如果显式捕获self,则在 closure 使用时,则允许隐式使用self。即在 closure 捕获列表中声明[self], 则 closure 内调用self.的地方都可以不用书写该self.。这个特性在SE-0269中提议。现在本篇提议想把这个特性支持扩展到weak self的捕获上,并允许隐式self和已解包的self一样使用。效果就是如果在 closure 内 self 已经解包,则 closure 内调用 self 的地方可以不用写 self。如下例的dismiss方法调用:
DerekYuYi
2022/11/09
1.4K0
iOS工程师必看的 20 道 面试题
本文收录总结了常见的 Swift 和 Objective-C 的面试题,希望对大家有所帮助。
会写bug的程序员
2020/06/09
3.9K0
iOS工程师必看的 20 道 面试题
ARC(Automatic Reference Counting )技术概述
此文章由Tom翻译,首发于csdn的blog 转自:http://blog.csdn.net/nicktang/article/details/6792972  Automatic Reference
用户1941540
2018/05/11
1.7K0
用 SwiftLint 保持 Swift 风格一致
代码风格可能是一个有争议的话题,并且在开发人员之间引发一些激烈的讨论。使用工具强制执行一套代码风格规则对于避免一些争论,以及确保在整个项目中保持代码风格的一致性非常有帮助。SwiftLint 可以很容易的整合进 Xcode 项目中,以便在编译时将代码风格冲突标记为警告或者错误。
Swift社区
2022/12/12
2.4K0
用 SwiftLint 保持 Swift 风格一致
iOS面试题-Swift篇
面试题持续整理更新中,如果你正在面试或者想一起进阶,不妨添加一下交流群 1012951431一起交流。
会写bug的程序员
2020/06/28
3.7K0
iOS面试题-Swift篇
从 SIL 角度看 Swift 中的值类型与引用类型
在 Swift 开发过程中,你很可能至少问过自己一次struct与class之间的区别,即使你自己没问过,你的面试官应该也问过。对这个问题的答案中,可能最大的区别就是一个是值类型,而另一个是引用类型,今天我们就来具体聊聊这个区别。
CoderStar
2022/09/23
2.3K0
用Swift写一个响应式编程库
本文介绍了如何使用 Reactive Programming 的方式在 Swift 中实现信号量,通过使用 Signal 和 Disposable 两个概念来模拟实现信号量,以解决在多线程环境下对共享资源的访问控制问题。同时,也介绍了一种使用 Combine 框架来实现线程安全的信号量,以及如何使用 Combine 来实现一个类似于 RxSwift 的响应式编程库。
企鹅号小编
2018/01/03
1.1K0
46 道 Swift 常见面试题解
3、Set 独有的方法有哪些? 4、实现一个 min 函数,返回两个元素较小的元素 5、map、filter、reduce 的作用 6、map 与 flatmap 的区别 7、什么是 copy on write 8、如何获取当前代码的函数名和行号 9、如何声明一个只能被类 conform 的 protocol 10、guard 使用场景 11、defer 使用场景 12、String 与 NSString 的关系与区别 13、怎么获取一个 String 的长度 14、如何截取 String 的某段字符串 15、throws 和 rethrows 的用法与作用 16、try?和 try!是什么意思 17、associatedtype 的作用 18、什么时候使用 final 19、public 和 open 的区别 20、声明一个只有一个参数没有返回值闭包的别名
Swift社区
2021/11/26
5.5K0
相关推荐
Swift基础 自动参考计数
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验