7 月活动,关注公众号抽奖
又到了我们每月一次的活动日了。今天我们还是抽奖,送出 10 枚 MWeb for Mac 的兑换码。MWeb 是一款专业的 Markdown 写作、记笔记、静态博客生成软件,功能相当强大,相信用过的童鞋都知道。作者
oulvhai
,目前是独立开发者。这里感谢 oulvhai 为我们提供的兑换码。
MWeb 相关的介绍大家可以查看 官网 ,我们这次的兑换码是非 Mac App Store 版,还请中奖的小伙伴在官网下载试用版,然后激活即可。
上周内容回顾
上周公众号发布的以下文章:
本期知识小集的主要内容包括:
- 一个关于 GCD 分组任务的小 tip
- 一次内存泄漏后的思考
- UIAlertView 与输入框结合使用时的一个坑
- 提高 Shortcuts 调试效率的小技巧
- Xcode 断点调试时打印变量值报错的问题(编译优化相关)
- Watch OS 4 新 API 解决手表自动休眠问题
一个关于 GCD 分组任务的小 tip
作者 : halohily
在项目中看到一段使用 GCD group 处理的代码,简化下来大概如下图
dispatch_group_notify
的调用放在了
dispatch_group_async
的 block 中,乍一看会有是否产生永久阻塞的疑问,因为子任务完成后的派发任务被放在了一个子任务中。然而其实这是不会阻塞的,代码会按编写人的预期进行执行,即 log1 输出之后,输出 log2。这是因为 dispatch_group_notify 的 block 是异步执行的。
再举个例子,如下图,执行结果依次会是:log 1,log 2 ,log 4 ,log 5 ,log 3。
虽然此处结果正确,但这种将 dispatch_group_notify 的调用放在某一个子任务的执行块中的写法是不被推荐的,它不但反逻辑,而且并不总能保证结果正确。比如如果在此例中,在调用了 dispatch_group_notify 的子任务之后,又为该任务组使用 dispatch_group_async 语句添加后续子任务,这时代码的执行结果是不确定的。
既然最开始的例子中执行结果是正确的,有的同学会问,如果把 dispatch_group_notify 的调用放在所有子任务的最前面,如下图,是否也能获得预期的结果呢?答案是否定的,因为在最开始调用 dispatch_group_notify 时,子任务数量为0,它的代码块会立即执行。而后为该组派发了多个子任务,当这些子任务都执行完毕后,也并不会再次触发 dispatch_group_notify 的代码块。
一次内存泄漏后的思考
作者 : Lefe_x
最近项目中遇到一个内存泄漏的问题,SecondViewController 这个类在 pop 后并没有执行 dealloc 方法,也就没有被正常被释放。使用内存泄漏工具排查,并没有发现有循环引用的地方,手动查了一下也没发现异常。正在迷茫的时候,突然看到了一个注册监听的地方。实现方式类似下面这样:
- (void)dealloc {
[[Manager sharedInstance] removeObserver:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[[Manager sharedInstance] addObserver:self];
}
复制代码
看到这里你应该已经猜到 SecondViewController 为什么没被释放,它被 Manager 持有了,而 Manager 是一个单例,自然 SecondViewController 也不会被释放,dealloc 方法也不会执行。
这种设计很常见,往往给某个服务注册监听,达到类似通知的效果。如果使用数组保存监听者,监听者将会被数组持有。有同学可能说,可以在 viewDidAppear 注册,在 viewWillDisappear 移除,这样 SecondViewController 就会被释放。但是,这样设计很糟糕,我们尽量不去约束调用者如何调用某个 API。
其实正确的做法是使用一个弱引用容器,我们可以使用 NSHashTable 来保存监听者,这样当监听者释放后,将自动从 NSHashTable 中移除,也不需要主动调用移除监听者的方法(也可以调用,视情况而定)。下面是一个简单的实现,你也可以参考 YYTextKeyboardManager 的实现:
_listenerTable = [NSHashTable weakObjectsHashTable];
- (void)addObserver:(NSObject *)obj {
[self.listenerTable addObject:obj];
}
- (void)removeObserver:(NSObject *)obj {
[self.listenerTable removeObject:obj];
}
复制代码
UIAlertView 与输入框结合使用时的一个坑
作者 : Vong_HUST
相信
UIAlertView
大家应该都很熟悉,但是最近遇到一个坑。
由于历史原因,项目中还在大量使用 UIAlertView。某天测试过来反馈说,评论框字符长度超过最大长度时,点击发送,弹出一个
alert
提示,点击确定后,评论框无法在被激活,也就是没法弹出键盘了。很是怪异,
debug
无果,搜了一下
stackoverflow
,发现有人遇到过类似的问题,可以点击末尾的参考链接来查看具体详情。
他给出的解决方案就是把这种情况下的 UIAlertView 换成 UIAlertController。试了下这种方式,果然是可行的,由于之前 UIAlertView 是不依赖其它视图层级的,创建后直接
show
就可以了,所以很多地方直接写在了非视图控制器类中。在换成 UIAlertController 之后,由于它是继承自 UIViewController 的,所以必须要有 VC 把它
present
起来。解决方案也很简单,写一个 UIViewController 的分类获取当前顶部可见的 ViewController,然后在上面
present
出 UIAlertController 即可,获取顶部可见 ViewController 的代码随便一搜就可以找到,这边就不贴了。
PS:UIAlertController 是 iOS8 以后才提供的,不过相信大家也不用适配 iOS8 之前的系统了吧😂。如果还要适配,那就只能做版本区分了。。。
参考
iOS 9 - Keyboard pops up after UIAlertView dismissed
提高Shortcuts调试效率的小技巧
作者 : 高老师很忙
iOS12提供了
Shortcuts
的功能,今天给大家介绍 2 个苹果提供的提高 Shortcuts 调试效率的小技巧。