The*_*imp 5 objective-c nsoperation cllocationmanager ios
我正在努力利用CLLocationManager一个NSOperation.作为其中的一部分,我需要能够startUpdatingLocation在完成操作之前等待直到收到CLLocation.
目前我已经完成了以下操作,但是似乎从未调用过委托方法.有人可以建议问题是什么吗?
- (void)main
{
@autoreleasepool {
if (self.isCancelled)
return;
// Record the fact we have not found the location yet
shouldKeepLooking = YES;
// Setup the location manager
NSLog(@"Setting up location manager.");
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
while (shouldKeepLooking) {
if (self.isCancelled)
return;
// Do some other logic...
}
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
// None of this ever seems to be called (despite updating the location)
latestLocation = [locations lastObject];
[manager stopUpdatingLocation];
shouldKeepLooking = NO;
}
Run Code Online (Sandbox Code Playgroud)
回到runloop讨论,这是我在基础NSOperation实现中通常解决的问题:
// create connection and keep the current runloop running until
// the operation has finished. this allows this instance of the operation
// to act as the connections delegate
_connection = [[NSURLConnection alloc] initWithRequest:[self request]
delegate:self];
while(!self.isFinished) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
}
Run Code Online (Sandbox Code Playgroud)
我关键isFinished,我通过设置器更新isCancelled和isFinished.这是isCancelledsetter的一个例子:
- (void)setIsCancelled:(BOOL)isCancelled {
_isCancelled = isCancelled;
if (_isCancelled == YES) {
self.isFinished = YES;
}
}
Run Code Online (Sandbox Code Playgroud)
那就是说,我提出了一些关于为什么这是必要的问题.如果在找到位置之前不需要启动某些东西,为什么不在主线程上启动位置管理器,等待相应的委托回调然后启动后台操作?
更新:更新解决方案
虽然最初的答案通常都有,但我已经完全实现了一个解决方案,它确实需要对管理运行循环的方式稍作改动.也就是说,所有代码都可以在GitHub上找到 - https://github.com/nathanhjones/CLBackgroundOperation.以下是该方法的详细说明.
文艺青年最爱的
更改
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
Run Code Online (Sandbox Code Playgroud)
至
[[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes
beforeDate:[NSDate distantFuture]];
Run Code Online (Sandbox Code Playgroud)
细节
在您的操作界面中定义以下三个属性.我们将指出这些操作是并发的,因此我们将手动管理它们的状态.在GitHub的解决方案中,这些是其中的一部分NJBaseOperation.
@property(nonatomic,assign,readonly) BOOL isExecuting;
@property(nonatomic,assign,readonly) BOOL isFinished;
@property(nonatomic,assign,readonly) BOOL isCancelled;
Run Code Online (Sandbox Code Playgroud)
在您的操作实现中,您将要进行这样的readwrite,如下所示:
@interface NJBaseOperation ()
@property(nonatomic,assign,readwrite) BOOL isExecuting;
@property(nonatomic,assign,readwrite) BOOL isFinished;
@property(nonatomic,assign,readwrite) BOOL isCancelled;
@end
Run Code Online (Sandbox Code Playgroud)
接下来,您将要合成上面定义的三个属性,以便您可以覆盖setter并使用它们来管理您的操作状态.这是我通常使用的,但有时setIsFinished:根据我的需要在方法中添加了一些额外的语句.
- (void)setIsExecuting:(BOOL)isExecuting {
_isExecuting = isExecuting;
if (_isExecuting == YES) {
self.isFinished = NO;
}
}
- (void)setIsFinished:(BOOL)isFinished {
_isFinished = isFinished;
if (_isFinished == YES) {
self.isExecuting = NO;
}
}
- (void)setIsCancelled:(BOOL)isCancelled {
_isCancelled = isCancelled;
if (_isCancelled == YES) {
self.isFinished = YES;
}
}
Run Code Online (Sandbox Code Playgroud)
最后,为了使我们不必手动发送KVO通知,我们将实现以下方法.这是有效的,因为我们的属性已命名isExecuting,isFinished并且isCancelled.
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key {
return YES;
}
Run Code Online (Sandbox Code Playgroud)
现在,操作基础已经完成,是时候淘汰位置了.您将要覆盖main并在其中启动您的位置管理器并指示当前的运行循环继续运行,直到您另外告诉它.这可确保您的线程可以接收位置委托回调.这是我的实现:
- (void)main {
if (_locationManager == nil) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[_locationManager startUpdatingLocation];
}
while(!self.isFinished) {
[[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes
beforeDate:[NSDate distantFuture]];
}
}
Run Code Online (Sandbox Code Playgroud)
您应该收到一个委托回调,此时您可以根据位置进行一些工作,然后完成操作.这是我的实现,计入10,000,然后清理.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSLog(@"** Did Update Location: %@", [locations lastObject]);
[_locationManager stopUpdatingLocation];
// do something here that takes some length of time to complete
for (int i=0; i<10000; i++) {
if ((i % 10) == 0) {
NSLog(@"Loop %i", i);
}
}
self.isFinished = YES;
}
Run Code Online (Sandbox Code Playgroud)
GitHub上的源包含一个dealloc实现,它只是记录它被调用,并且还观察到operationCount对我的更改NSOperationQueue并记录计数 - 指示它何时回落到0.希望有所帮助.如果您有疑问,请告诉我.
它将在与 main 运行相同的操作队列中调用委托方法。 NSOperation 队列默认是串行的。您的 while 循环只是永远旋转(因为操作永远不会取消),并且对委托方法的调用位于其后面的队列中,永远无法运行。
完全摆脱 while 循环并让操作完成。然后,当调用委托方法时,如果取消,则通过返回丢弃结果。
| 归档时间: |
|
| 查看次数: |
3646 次 |
| 最近记录: |