我有一个带有标签栏和3个不同UIViewControllers
的iOS应用,每个标签一个。该应用程序使用SudzC与C# .NET webservice
接口以从数据库中提取数据。
从所有三个视图控制器调用一个webservice方法,但我想强制只有一个视图控制器可以在任何时间点调用该方法,并且在返回数据之前没有其他视图控制器可以调用它
我尝试通过在AppDelegate
中定义NSLock,然后在每个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];
}
webservice返回的处理程序定义为(为清晰起见而截断)
-(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锁已经被困住了。
答案 0 :(得分:0)
在我看来,你不应该为这个简单的案例使用锁(这是“邪恶的”)。
您可以尝试使用的是NSOperationQueue,设置为一次管理1个并发操作,然后让视图控制器将其Web服务调用入队:操作队列将保证一次只能执行一个操作执行。 操作队列的另一个优点是视图控制器可以检查队列是否为空,然后根据当前状态决定是否将其调用入队。 最后,您可以使用KVO观察队列状态,以便每个视图控制器可以在提交新请求之前检查这一点。
与使用NSOperationQueue类似,另一种可能性是创建一个私有GCD串行队列,并再次将所有Web服务请求排入队列(包含在块内)。虽然GCD串行队列比NSOperationQueues(恕我直言)更容易实现,但它们不具备可观察性和取消操作的可能性。
答案 1 :(得分:0)
如果它只是您想要一次访问Web服务的1个视图。你可以使用Singleton类。 这是网上许多例子之一的链接。 http://www.galloway.me.uk/tutorials/singleton-classes/
您也可以使用NSUserDefaults存储bool值,以通知您视图是否正在使用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
}
我希望这会对你有所帮助。快乐的编码。!!