【发布时间】:2013-08-24 20:05:15
【问题描述】:
我正在实现一个通过用户输入动画的健康栏。
这些动画使其上升或下降一定量(例如 50 个单位),并且是按下按钮的结果。有两个按钮。增加和减少。
我想在健康栏上执行一个锁,这样一次只有一个线程可以更改它。问题是我遇到了死锁。
我猜是因为一个单独的线程运行一个由另一个线程持有的锁。但是当动画完成时,那个锁就会让位。如何实现一个在 [UIView AnimateWithDuration] 完成时结束的锁?
我想知道NSConditionLock 是否可行,但我想尽可能使用 NSLocks 以避免不必要的复杂性。你有什么推荐的?
(最终我想让动画“排队”,同时让用户输入继续,但现在我只想让锁工作,即使它首先阻止输入。)
(嗯,想想看,同一个 UIView 一次只有一个 [UIView AnimateWithDuration] 运行。第二次调用将中断第一次调用,导致完成处理程序立即为第一次运行。也许是第二次锁定在第一个有机会解锁之前运行。在这种情况下处理锁定的最佳方法是什么?也许我应该重新访问 Grand Central Dispatch,但我想看看是否有更简单的方法。)
在 ViewController.h 我声明:
NSLock *_lock;
在 ViewController.m 我有:
在加载视图中:
_lock = [[NSLock alloc] init];
ViewController.m 的其余部分(相关部分):
-(void)tryTheLockWithStr:(NSString *)str
{
LLog(@"\n");
LLog(@" tryTheLock %@..", str);
if ([_lock tryLock] == NO)
{
NSLog(@"LOCKED.");
}
else
{
NSLog(@"free.");
[_lock unlock];
}
}
// TOUCH DECREASE BUTTON
-(void)touchThreadButton1
{
LLog(@" touchThreadButton1..");
[self tryTheLockWithStr:@"beforeLock"];
[_lock lock];
[self tryTheLockWithStr:@"afterLock"];
int changeAmtInt = ((-1) * FILLBAR_CHANGE_AMT);
[self updateFillBar1Value:changeAmtInt];
[UIView animateWithDuration:1.0
delay:0.0
options:(UIViewAnimationOptionTransitionNone|UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionAllowUserInteraction)
animations:
^{
LLog(@" BEGIN animationBlock - val: %d", self.fillBar1Value)
self.fillBar1.frame = CGRectMake(FILLBAR_1_X_ORIGIN,FILLBAR_1_Y_ORIGIN, self.fillBar1Value,30);
}
completion:^(BOOL finished)
{
LLog(@" END animationBlock - val: %d - finished: %@", self.fillBar1Value, (finished ? @"YES" : @"NO"));
[self tryTheLockWithStr:@"beforeUnlock"];
[_lock unlock];
[self tryTheLockWithStr:@"afterUnlock"];
}
];
}
-(void)updateFillBar1Value:(int)changeAmt
{
self.prevFillBar1Value = self.fillBar1Value;
self.fillBar1Value += changeAmt;
if (self.fillBar1Value < FILLBAR_MIN_VALUE)
{
self.fillBar1Value = FILLBAR_MIN_VALUE;
}
else if (self.fillBar1Value > FILLBAR_MAX_VALUE)
{
self.fillBar1Value = FILLBAR_MAX_VALUE;
}
}
输出:
复制说明:点击“减少”一次
touchThreadButton1..
tryTheLock beforeLock.. 免费。
tryTheLock afterLock.. 锁定。 开始动画块 - val: 250 结束动画块 - val:250 - 完成:是
在解锁之前尝试TheLock.. 已锁定。
在解锁后尝试锁定.. 免费。
结论:这符合预期。
--
输出:
重现说明:快速点击“减少”两次(中断初始动画)..
touchThreadButton1..
tryTheLock beforeLock.. 免费。
tryTheLock afterLock.. 锁定。 开始动画块 - val: 250 touchThreadButton1..
tryTheLock beforeLock.. 锁定。 * -[NSLock lock]: 死锁 ('(null)') * 中断 _NSLockError() 以进行调试。
结论。死锁错误。用户输入被冻结。
【问题讨论】:
标签: ios multithreading nslock animatewithduration