0

我有一个带有标签栏和 3 个不同的 iOS 应用程序,UIViewControllers每个标签一个。该应用程序使用 SudzC 与 a 交互以C# .NET webservice从数据库中提取数据。

从所有三个视图控制器调用一个 web 服务方法,但我想强制只有一个视图控制器可以在任何时间点调用该方法,并且在返回数据之前没有其他视图控制器可以调用它。

我试图通过在 NSLock 中定义一个 NSLock 来解决这个问题AppDelegate,然后在每个中实现以下代码viewController

if([SharedAppDelegate.loginLock lockBeforeDate:[[[NSDate alloc] init] dateByAddingTimeInterval:30.0]])
{
     // got the lock so call the webservice method
     SDZiOSWebService* webService = [SDZiOSWebService service];
     [webService Login:self action:@selector(handleRelogin:) username:userName password:password];
}
else
{
     // can't get lock so logout
     self->reloginInProgress = false;
     [SharedAppDelegate doLogout];
}

Web 服务返回的处理程序定义为(为清楚起见截断)

-(void)handleRelogin: (id) result {
     SDZLoginResult *loginResult = (SDZLoginResult*)result;
     if(loginResult.Status)
     {
          SharedAppPersist.key = loginResult.key;
     }
     else
     {
          SharedAppPersist.key = @"";
     }
     [SharedAppDelegate.loginLock unlock];
}

我的理解是第一个UIViewController会获得锁,而其他人会阻塞长达 30 秒以等待获得锁。但是,在极少数情况下,不止一个人同时viewController尝试访问锁,我会立即收到以下错误:

*** -[NSLock lockBeforeDate:]: deadlock (<NSLock: 0x2085df90> '(null)')

谁能告诉我我做错了什么?我对 C/C++ 中的锁有很好的理解,但是这些 Objective-C 锁被难住了。

4

2 回答 2

0

在我看来,对于这种简单的情况,您不应该使用锁(这是“邪恶的”)。

您可以尝试使用一个 NSOperationQueue,设置为一次管理 1 个并发操作,然后让视图控制器将其 Web 服务调用排队:操作队列将保证一次只执行一个操作。操作队列的另一个优点是视图控制器可以检查队列是否为空,然后根据当前状态决定是否将其调用加入队列。最后,您可以使用 KVO 来观察队列状态,因此每个视图控制器都可以在提交新请求之前简单地检查这一点。

另一种可能性,类似于使用 NSOperationQueue,是创建一个私有 GCD 串行队列并再次将所有 Web 服务请求排入队列(包装在一个块内)。虽然 GCD 串行队列比 NSOperationQueues (IMHO) 更易于实现,但它们并没有提供相同的可观察性优势和取消操作的可能性。

于 2013-01-23T10:52:08.473 回答
0

如果只是您希望 1 个视图一次访问 Web 服务。您可以使用单例类。这是网络上许多示例之一的链接。 http://www.galloway.me.uk/tutorials/singleton-classes/

您也可以使用 NSUserDefaults 存储一个布尔值,以通知您视图是否正在使用 Web 服务。一个简单的例子是:

储存价值

[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"active_connection"];
[NSUserDefaults synchronize];

检索

if(![[NSUserDefaults standardUserDefaults] boolForKey:@"active_connection"]) {
   [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"active_connection"];
   [NSUserDefaults synchronize];
   // Send request to web-service
}

我希望这可以帮助你。快乐编码.!!

于 2013-01-23T10:52:49.167 回答