使用Xcode 9工具查找运行时错误

可能的情况

1 –数据竞赛

在多个线程之间共享的任何可变数据都需要访问同步。 如果在共享的可变变量上缺少同步 ,则意味着您存在数据竞争。 在存在数据争用的情况下,我们的程序可能会发生内存损坏和崩溃。 这些问题适用于C语言,也适用于Swift代码。 因此,让我们看一下Swift中的示例。

在这种情况下,我们有一个名为EventLog的类,它仅具有一个简单的名为log的函数,该函数将一些文本消息输出到输出中。 但是它也跟踪哪个是调用该log方法的最后一个事件源。 它将信息保存到一个名为lastEventSource的存储属性中该属性是一个可选变量,在开始时为nil,但是一旦有人调用log,就会使用该特定日志源完美填充该信息。

现在让我们说我们有两个线程都试图同时调用该log方法。 假设第一个线程是我们的网络子系统,并且记录了一些下载已完成。 当第二个线程(代表我们的数据库子系统)正在记录查询已完成时:

那是一场数据竞赛,因为我们正在同时访问相同的内存位置。 Thread Sanitizer将对此发出警告!

要解决此问题,我们需要引入同步,最简单的方法是使用串行调度队列。

现在,由于此队列是串行的,因此一次只能执行一个工作项。 因此,如果将log函数的主体包装到queue.async中,将提供正确的同步。 并请注意,我在这里使用async是因为我们不需要等待该函数完成,因为该函数不会提供任何结果,因此等待它是没有意义的。 因此,这不仅解决了该问题,而且还提高了性能,因为现在无论呼叫日志的人都不再需要等待此打印完成。

这样,整个类现在都是线程安全的,我们可以从多个线程调用log 。 由Grand Central Dispatch或GCD提供的Dispatch队列在Swift中很容易获得,它们应该是同步的首选。 即使还有其他提供同步的机制,GCD也非常轻巧,并且可以从Swift轻松使用。

提示:一个好主意是将数据与串行调度队列相关联,并且仅访问这些队列中的数据,这将确保您仅以同步方式使用数据。