「 iOS知识小集 」2018 · 第 22 期

2,314 阅读7分钟

小集微博话题 #iOS知识小集# 阅读量已达到 1500w+,小小成就。欢迎更多童鞋加入一起来分享。

上周公众号发布的以下文章:

本期知识小集的主要内容包括:

  • iOS 内存泄露工具

  • 静态 UITableView 两种 style 的差异

  • 怎么解决网络请求的依赖关系

  • 对 AppStore 在蜂窝网150MB的下载限制的理解

  • 配置 xcodebuild 命令打包支持 Bitcode

  • Swift 版本建私有库时需要注意的地方

iOS 内存泄露工具

作者: Lefe_x

在日常开发中总会遇到内存泄漏的的问题,而排除内存泄漏一般会依靠以下这些工具:

  • MLeaksFinder

这个 WeRead 团队开发的一个内存泄漏检测工具,主要用来检测 UIViewController 和 UIView 中存在的内存泄漏。如果检查到内存泄漏,会弹出 Alert 提示存在内存泄漏。当然,如果某个 UIViewController 是单例,将会误检。

如果检查出内存泄漏,点击 Alert 上的 Retain Cycle 将使用 FBRetainCycleDetector 检查存在循环引用的对象。比如:

-> DownloadAudioListViewController ,
-> _callblock -> __NSMallocBlock__ 
  • FBRetainCycleDetector

这是 facebook 开源的一个内存泄漏检测工具,它可以检测出循环引用:

FBRetainCycleDetector *detector = [FBRetainCycleDetector new];
[detector addCandidate:myObject];
NSSet *retainCycles = [detector findRetainCycles];

检查出的内存泄漏将打印出来:

-> DownloadAudioListViewController ,
-> _callblock -> __NSMallocBlock__ 
  • Instrument 的 Leak 工具

Instrument 中的 Leak 工具主要用来“突袭”,开发者定期地使用它来检测内存泄漏。而上面介绍的工具主要在开发过程中即可发现内存问题,提前暴露给开发者。

Xcode 中的 Debug Memory Graph

这个工具主要以图表的形式显示了当前内存的使用情况,可以查看循环引用,如果有内存问题会显示一个叹号。

静态 UITableView 两种 style 的差异

作者: Vong_HUST

想必设置页应该是各大应用所必备的,相信大部分还是采用静态 UITableView 的方式在构建,我们项目中也用到了。最近测试反馈一个问题就是一些配置项的描述文案会盖住单元格内容,如图所示。由于之前配置项比较少,所以没有发现,最近新增了好几个配置,所以问题暴露出来了。

图中【接收哪些人】的私信是一个 SectionFooter,由于 SectionFooter 是悬停的,内容超过一屏的情况下,SectionFooter 会将单元格挡住,由于 footer 背景是透明的,所以看起来是重叠的。由于 tableView 设置的 style 是 Plain 的,这种情况下 SectionFooter 和 SectionHeader 都是悬停的。如果要想他们不悬停,只需要把 tableView 的 style 设置成 Grouped 即可。

但是需要注意的是 Grouped 样式的 SectionFooter 是自带间隔的,会比 Plain 样式下的 SectionFooter 高 18pt,所以改成 Grouped 样式之后如果要同步 Plain 样式的间隔,这个 tableView:heightForFooterInSection: 代理方法返回的高度要减小 18。

怎么解决网络请求的依赖关系

作者: 蒋匿

怎么解决网络请求的依赖关系:当一个接口的请求需要依赖于另一个网络请求的结果?

  1. 思路 1:操作依赖:NSOperation 操作依赖和优先级。

例如[operationB addDependency:operationA]; 虽然这个想法很好,但不适用异步,异步网络请求并不是立刻返回,无法保证回调时再开启下一个网络请求。

  1. 思路 2:逻辑判断:在上一个网络请求的响应回调中进行下一网络请求的激活。

这是最原始的想法,但还是有 BUG:可能拿不到回调无法执行到 block 块里面的代码。

  1. 思路 3:线程同步 -- 组队列(dispatch_group)。

先建一个全局队列 queue,并新建一个 group(用 dispatch_group_create()),然后向 Group Queue 依次追加 block,最后用 dispatch_group_notify 添加 block。当前面的 block 全部执行完,就会执行最后的 block。例如下图。

  1. 思路4:线程同步 --任务阻塞(dispatch_barrier)。

通过 dispatch_barrier_async 添加的操作会暂时阻塞当前队列,即等待前面的并发操作都完成后执行该阻塞操作,待其完成后后面的并发操作才可继续。使用 dispatch_barrier_async 可以实现类似组队列的效果。例如下图。

  1. 思路5:线程同步 -- 信号量机制(dispatch_semaphore)。

除了任务阻塞,还可以利用信号量实现这种阻塞效果:在异步开启任务 1 和任务 2 之前,初始化一个信号量并设置为 0,然后在任务 1 的 block 中写好请求操作,操作执行完后对前面的信号量加 1,在任务 2 的 block 中,需要在开始请求之前加上等待信号量的操作。这样一来,只有任务 1 中的请求执行完后,任务 2 等到了信号量加 1 才接着执行它的请求。例如下图。

对 App Store 在蜂窝网 150MB 的下载限制的理解

作者: 高老师很忙

大家应该都有这样的一个印象:在蜂窝网下,150MB 的包在 AppStore 是不能下载的,每当看到 AppStore 下面展示的 Size 接近 150MB 的时候就会很紧张,这意味着又要来一波艰难的减包操作了。

那么这个 150MB 指的是什么呢?是 AppStore 展示的 Size 么?我做了一个小小的调研,发现并非如此,150MB 是包的下载大小,而 AppStore 里展示的 Size 是安装后(有解压操作)的大小,对几个 App 进行了抓包操作:(这个是前段时间的调研,因为版本迭代可能数据会有出入,但足以说明问题)

从苹果之前的官方新闻也能看出端倪:

所以说 AppStore 蜂窝下载限制指的是下载的实际大小而非 AppStore 展示的 Size。

在 ITC 构建版本处理完成后,可以看到详细信息:在各个机型上的下载大小以及安装大小,同时也会提示你是 150MB 下载限制,超过限制还会给你一个黄色警告哦。

减包是一个任重而道远的事情,不要等到在 150MB 的危险边缘再去处理哦!

配置 xcodebuild 命令打包支持 Bitcode

作者: KANGZUBIN

我们通常会把一些公用的模块抽离出来打成一个 或者 .framework 动态库,然后再嵌入到宿主工程中。

最近我们的 App 工程开启 Bitcode 编译选项后(Enable Bitcode = YES),发现在进行 Archive 归档打 Release 包时,报如下错误,提示说工程使用的 libTestStaticSDK.a 静态库不支持 Bitcode:

ld: bitcode bundle could not be generated because '/.../TestApp/TestStaticSDKLib/libTestStaticSDK.a(TestStaticSDK.o)' was built without full bitcode. All object files and libraries for bitcode must be generated from Xcode Archive or Install build for architecture armv7

但是我们的 libTestStaticSDK 静态库工程的 Build Settings 中同样是有配置开启 Bitcode 的,为什么打出来的 .a 包却不支持 Bitcode 呢?

通过查阅 StackOverflow 我们发现,原来开启 Bitcode 后,在 Xcode 中进行 "Build" 或 "Archive" 时,Xcode 会自动在编译命令后面添加 -fembed-bitcode 标识,而如果使用 xcodebuild 命令进行打包,则需要手动添加一个 OTHER_CFLAGS,如下:

xcodebuild build OTHER_CFLAGS="-fembed-bitcode" -target libTestStaticSDK ...

另外一种解决方案是,在静态库 Xcode 工程的 Build Settings 中,添加一个 "User-Define Setting",内容为:'BITCODE_GENERATION_MODE' => 'bitcode',如下图所示:

这样在使用 xcodebuild 命令时就不用添加 OTHER_CFLAGS="-fembed-bitcode" 了。

综上,为了通用,我们可以在 xcodebuild 命令后同时添加上述两种标识,因此一个完整的静态库打包脚本大致如下(同样适用于 Framework 的打包):

参考链接

How do I xcodebuild a static library with Bitcode enabled?

https://stackoverflow.com/questions/31486232/how-do-i-xcodebuild-a-static-library-with-bitcode-enabled

iOS 中动/静态库支持 Bitcode 的问题

https://juejin.cn/post/6844903581447897101

Swift 版本建私有库时需要注意的地方

作者: 这个汤圆没有馅

利用 cocoapods 建 swift 版本私有库步骤和 OC 版本一样,只要把语言 Objc 切换成 Swift 即可。一般情况下,pod lib lint验证会报警告,如下图,加 --allow-warnings 直接忽略即可。

但是如果私有库里依赖了其他三方库,且该三方库的 swift 版本不一致,则 pod lib lint 会报一堆 error,如下图。

这个时候就需要根据警告里的提示配置 .swift-version。该文件默认情况是不会有的,需要手动添加,如下图。这个时候再次执行 pod lib lint --allow-warnings 验证就能通过。

关注我们

欢迎关注我们的公众号:iOS-Tips,也欢迎加入我们的群组讨论问题。可以公众号留言 ios、flutter、web、pwa、小程序 等关键词获取入群方式。