gpt4 book ai didi

ios - 当所有代码都在主线程上时如何优雅地锁定(寻找 NSLock 的替代方案)

转载 作者:行者123 更新时间:2023-11-29 12:24:24 27 4
gpt4 key购买 nike

在这种情况下,我必须等待 UIKit 动画完成,并且我正在使用完成 block 来执行相关的最终代码。现在我已经意识到,当我从主线程调用该函数两次时,我可以触发一个引入错误的竞争条件。我无法使用简单的@synchronised(self) 锁,但我有一个使用 NSLock 的不同解决方法。我想知道是否有更优雅的解决方案。

为了给出使用它的一些上下文,我有许多 View 通过 UIAttachmentBehaviour (UIKit Dynamics) 相互连接,以进行一些物理动画。当我滑动 View 时,它被替换并且动画看起来像是 View 正在滑入/滑出(简单翻译)。在我的解决方案中,我删除了附件行为,否则物理附件将跟随滑动 View ,这不是我想要的。

有问题的代码如下所示:

- (void)handleGesture;
{
// [A]
// remove UIAttachmentBehaviours (UIKit dynamics) between the static views and the view that fades out
...
// animate translation of fade-out and fade-in views
[UIView animateWithDuration:0.5
animations:^{
// [B]
for (UIView* view in swipeAllViews)
{
CGPoint location = view.center;
location.x += 2*screenWidth;
view.center = location;
}
}
completion:^(BOOL finished) {
// [C]
for (UIView* view in swipeOutViews)
{
[view removeFromSuperview];
}

for (UIView* view in swipeInViews)
{
// do some setup
}

// add UIAttachmentBehaviour between the static views and the new view that fades in
}
];

}
}

请注意,很难手动触发该问题,但如果您以编程方式调用代码片段,执行顺序会略有不同。为了给出一个想法,我用 A、B、C、D 标记了代码部分。让我们将第一条执行线的轨迹称为 1A...1D,将第二条调用称为 2A...2D。在正常情况下,所需的执行顺序类似于:

1A
0.5 seconds delay
1B
1C
2A
0.5 seconds delay
2B
2C

然而,当以编程方式调用 handleGesture 两次时,执行顺序是:

1A
2A
0.5 seconds delay
1B
1C
2B
2C

我想出的解决方法是这样的:

- (void)viewDidLoad;
{
self.theLock = [[NSLock alloc] init];
}

- (void)handleGesture;
{
if (![self.theLock tryLock])
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^(void){
[self handleGesture];
});
}
else
{
// remove some UIAttachmentBehaviours (UIKit dynamics)
...

// animate translation of views
[UIView animateWithDuration:0.5
animations:^{
for (UIView* view in swipeAllViews)
{
CGPoint location = view.center;
location.x += 2*screenWidth;
view.center = location;
}
}
completion:^(BOOL finished) {

for (UIView* view in swipeOutViews)
{
[view removeFromSuperview];
}

for (UIView* view in swipeInViews)
{
// do some setup
}

// add UIAttachmentBehaviours between the old and new views

[self.theLock unlock];
}
];

}
}

请注意,如果您调用 lock 而不是 tryLock,那么您将陷入死锁,因为代码是在主线程上执行的,如果它阻塞,动画将永远不会完成。

换句话说,当 handleGesture 被调用时,它会被锁定直到动画结束。如果在完成 block 之间或之后再次调用该函数,它会尝试获取锁。如果无法获取它,它会在 0.5 秒后重试(大约是动画应该花费的时间)。

现在我觉得这可能会成为一个用餐哲学家的问题,这让我想知道是否有更简单的解决方案。我以为在函数的开头加上一个@synchronised(self) 就可以解决这个问题,但是当动画操作被推送到主线程时,函数立即返回并且锁会被立即释放。

感谢您到目前为止的阅读。

最佳答案

我不建议在主线程上使用任何类型的锁(NSLock@synchronized 或信号量或任何东西)。

从理论上讲,您可以将动画包装在异步 NSOperation 子类中,例如 shown here .

坦率地说,考虑到他们在 iOS 8 中为可中断和响应式动画所做的所有努力,这一切似乎有点令人遗憾。请参阅 WWDC 2014 视频,Building Interruptible and Responsive Interactions .这个想法是,如果你在前一个动画的中途开始一个新动画,让它从第一个动画当前所在的位置平滑地拾取动画,而不是等待它完成或以其他方式中断它。我没有按照您的情况所需的最终用户体验来提出具体建议,但可能值得观看该视频,看看它是否能为您带来任何想法。

但我认为您可以使用状态变量来指示它是否需要执行 A 以及是否需要执行 C。最终产品将类似于:

1A1B(interrupt half way through 1B animation)(skip 2A)2B picks up where 1B left off(skip 1C)2C

我不确定你是否能理解我所说的,但这个想法可能是可中断的和响应式的交互以及 A 和 C block 的有条件执行(即如果这个动画没有打断之前的 Action 则只做 A一个;如果此动画未被后续动画打断,则仅执行 C)。

关于ios - 当所有代码都在主线程上时如何优雅地锁定(寻找 NSLock 的替代方案),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29687500/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com