以下代码会在 iOS 模拟器中产生崩溃。
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(dispatch_get_main_queue(), ^{
NSDate *sleepStart = [NSDate date];
while ([sleepStart timeIntervalSinceNow] > -300) {
}
});
}
Run Code Online (Sandbox Code Playgroud)
更新:即使在后台线程上也会出现此问题。
下面的代码也有错误:
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSDate *sleepStart = [NSDate date];
while ([sleepStart timeIntervalSinceNow] > -300) {
}
});
}
Run Code Online (Sandbox Code Playgroud)
就这样。将其粘贴到任何视图控制器中,在模拟器中运行该应用程序正好 4 分 15 秒,它就会崩溃。
这种崩溃是我以前从未见过的。是“EXC_???(11)”。奇怪的是,您可以在崩溃后按“继续”按钮,它会像平常一样继续。
为什么会崩溃?如何将长任务提交到队列而不导致此行为?
到目前为止,我尝试过以下一些方法,但还没有解开这个谜团:
更新#1
该问题仅在 LLDB 下重现,在 …
原则上,串行DispatchQueue会一个接一个地执行提交的任务。但是,如果在一项任务中触发了上下文切换(例如,调用sleep)怎么办?队列是立即执行下一个任务,还是等待当前任务完成?
对于此代码:
q.async {
print("IN 1")
var i = 1
while i < 10 {
Thread.sleep(forTimeInterval: 0.1)
i += 1
}
print("OUT of 1")
}
q.async {
print("IN 2")
}
Run Code Online (Sandbox Code Playgroud)
结果是:
// IN 1 -> OUT of 1 -> IN 2 ?
// or IN 1 -> IN 2 -> OUT of 1 ?
Run Code Online (Sandbox Code Playgroud)
我尝试在操场上运行代码,但似乎sleep(和Thread.sleep)在操场中不起作用。
multithreading grand-central-dispatch swift swift-playground
有没有比使用asyncAfter3 次更好的方法将这些动画间隔一秒?
let firstAnimationTime = DispatchTime.now()
let secondAnimationTime = DispatchTime.now() + 1
let thirdAnimationTime = DispatchTime.now() + 2
DispatchQueue.main.asyncAfter(deadline: firstAnimationTime) {
self.firstAnimation()
}
DispatchQueue.main.asyncAfter(deadline: secondAnimationTime) {
self.secondAnimation()
}
DispatchQueue.main.asyncAfter(deadline: thirdAnimationTime) {
self.thirdAnimation()
}
Run Code Online (Sandbox Code Playgroud) 我有一个 ViewController,它在 AddressBook 中获取数据。为了在获取数据时收到通知,我向此 ViewController 发布通知以允许它更新 NSViewTable(在主队列中)。当用户结束在 ViewController 视图中编辑 NSTextField 时,此 ViewController 会显示一个瞬态 NSPopover .
当我在此字段中输入第一个字符串时,弹出窗口将显示,然后在用户完成与其交互时关闭。如果我再次编辑文本字段,Popover 不会出现在视图中,但提取过程开始。当它结束并且DataUpdated专门用于通知帖子的方法被触发时。然后我dispatch_sync(dispatch_get_main_queue(), ^{在线路上崩溃了(控制台中没有消息,即使启用了 NSZombie)。这是弹出内容 ViewController 中的代码:
- (void) getContactForName: (NSString *) name
{
CNEntityType entityType = CNEntityTypeContacts;
if ([CNContactStore authorizationStatusForEntityType:entityType]){
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError * _nullableError){
if (granted) {
if ([CNContactStore class]){
NSError *contactError;
CNContactStore *addressBook = [[CNContactStore alloc] init];
[addressBook containersMatchingPredicate:[CNContainer predicateForContainersWithIdentifiers:@[addressBook.defaultContainerIdentifier]] error:&contactError];
NSArray * keysToFetch =@[CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactFamilyNameKey, CNContactGivenNameKey, CNContactIdentifierKey];
NSError *error; …Run Code Online (Sandbox Code Playgroud) 我正在开发一个应用程序,它使用一些框架通过 openGL 绘制 3D 人员。这个框架要求我draw() 从完全相同的线程调用方法。
所以我创建了一个串行 DispatchQueue 并在其中启动 CADisplayLink,draw()以 60FPS调用。我必须从这个确切的线程调用其他一些方法,例如start()和stop()。这使队列对我来说是完美的解决方案。
您可能知道 DispathQueue 不保证在同一线程上执行每个任务。这对我来说压力很大,因为它可能会破坏我的应用程序。
我真的不喜欢创建 NSThread 并在其上实现我自己的队列的想法。
有没有办法将 DispatchQueue 绑定到精确的线程?也许可以绑定 NSOperationQueue ?
这段代码会死锁,因为:
例如:
DispatchQueue.main.async {
print(Thread.current)
DispatchQueue.main.sync {
print(Thread.current)
print(2)
}
print(3)
}
Run Code Online (Sandbox Code Playgroud)
为什么在concurrentQueue不会造成死锁?他们也在同一个线程中。
DispatchQueue.global().async {
print(Thread.current)
DispatchQueue.global().sync {
print(Thread.current)
print(2)
}
print(3)
}
Run Code Online (Sandbox Code Playgroud) 我知道这两种之间的区别。
对于异步任务,下一个任务将在当前任务开始后运行,这意味着如果有可用线程,任务将被分派到多个线程。
对于同步任务,下一个任务将在当前任务完成后运行。
主线程如何运行异步任务,因为它只有一个线程?
这让我很困惑。
提前致谢。
使用这个答案作为参考,我试图在我的 swift linux 脚本中实现一个信号处理程序,它将使程序保持活动状态直到 Ctrl-C,然后在收到 SIGINT 时运行一些清理。使用该答案中的代码在主函数中效果很好:
import Dispatch
import Foundation
signal(SIGINT, SIG_IGN) // // Make sure the signal does not terminate the application.
let sigintSrc = DispatchSource.makeSignalSource(signal: SIGINT, queue: .main)
sigintSrc.setEventHandler {
print("Got SIGINT")
// ...
exit(0)
}
sigintSrc.resume()
dispatchMain()
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试将信号处理程序移动到一个函数中,如下所示:
public func registerSigint() {
signal(SIGINT, SIG_IGN)
let sigintSrc = DispatchSource.makeSignalSource(signal: SIGINT, queue: .main)
sigintSrc.setEventHandler {
print("Got SIGINT")
exit(0)
}
sigintSrc.resume()
}
Run Code Online (Sandbox Code Playgroud)
...
registerSigint()
dispatchMain()
Run Code Online (Sandbox Code Playgroud)
程序在 CTRL-C SIGINT 上无限期挂起。为什么这表现不同?
我看到很多这样的代码:
DispatchQueue.main.async {
self.tableView.reloadData()
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下, wheretableView是 的属性self,应该确保weak self像这样捕获:
DispatchQueue.main.async { [weak self] in
self?.tableView.reloadData()
}
Run Code Online (Sandbox Code Playgroud)
我认为是这样,但是这种类型的“不安全”代码在代码库中无处不在,我想知道我是否遗漏了什么?
通过使用以下代码,我期望每次调用 func 时,执行之间的最短时间为 3-4 秒。
但是:当我writeData()连续调用4 次时,我看到异步块在不等待前一次调用完成的情况下执行。
func writeData(){
DispatchQueue(label: "be.io").asyncAfter(deadline: .now() + 1) {
print("START :\(Int64((Date().timeIntervalSince1970 * 1000.0).rounded()))")
Thread.sleep(forTimeInterval: 3)
}
}
...
writeData()
writeData()
writeData()
writeData()
Run Code Online (Sandbox Code Playgroud)
预期的输出应该是这样的:
START :1611250630000
START :1611250634000
START :1611250638000
START :1611250642000
Run Code Online (Sandbox Code Playgroud)
但在执行时,我得到了所有 4 个调用相同的时间戳(大约 1 毫秒的差异)。
START :1611250630000
START :1611250630000
START :1611250630000
START :1611250630000
Run Code Online (Sandbox Code Playgroud)
我在做什么错?
PS我毫不拖延地尝试了异步,没有运气。