- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
注意:
这只是一个概念验证。
真正的后台任务将是不断请求原始数据的“HTTP Get”并通过主线程显示它;按需。
场景:
1)按需切换后台任务(循环)。
2) 后台任务每次迭代通知主线程UI。
3) 只有一 (1) 个 block 操作在队列中运行。
作案手法
1) 使用NSBlockOperation包含后台代码。
2) 使用区域 BOOL 来切换循环;通过 IBAction。
问题
1) 编译器将 BOOL 'isRunning' 标记为 strong 链接:
Capturing 'self' strongly in this block is likely to lead to a retain cycle.
2)在尝试添加 block 操作之前,我检查了队列中是否有任何操作。
但我总是得到以下错误:
-[NSOperationQueue addOperation:]: operation is finished and cannot be enqueued
除了上述问题之外,该概念验证似乎还有效。
问题:
1)当它只是一个缩放器时,为什么编译将 BOOL 'running' 标记为强行?
2)如果在队列中找不到任何东西,为什么我不能通过添加另一个 NSBlockOperation 来重用 NSOperationQueue?
以下是完整代码:
#define START 0
#define STOP 1
@interface ricViewController ()
@property (assign) BOOL running;
@end
@implementation ricViewController {
NSOperationQueue *operationQueue;
NSBlockOperation *blockOperation;
void (^backgroundBlock)(void);
}
@synthesize running = isRunning;
#pragma mark - ViewController methods
- (void)viewDidLoad {
operationQueue = [NSOperationQueue new];
[operationQueue setMaxConcurrentOperationCount:1];
[operationQueue setName:@"RicQueue"];
[self buildBackgroundBlock];
blockOperation = [NSBlockOperation blockOperationWithBlock:backgroundBlock];
[super viewDidLoad];
}
// -------------------------------------------------------------------------------------------------------------------
- (void)didReceiveMemoryWarning {
operationQueue = nil;
}
// -------------------------------------------------------------------------------------------------------------------
#pragma mark - Local methods
- (void)buildBackgroundBlock {
static int k = 0;
backgroundBlock = ^{
while (isRunning) { // 1) *** compiler warning flag: strong link warning ***
sleep(1);
if ([NSThread isMainThread]) {
NSLog(@"{backgroundBlock} *** Main Thread *** ***");
} else {
NSString *myString = [NSString stringWithFormat:@"{backgroundBlock} count = %i", k++];
NSLog(myString);
dispatch_async(dispatch_get_main_queue(), ^{
self.dataLabel.text = myString;
});
}
}
};
}
// -------------------------------------------------------------------------------------------------------------------
#pragma - Action methods
- (IBAction)exitAction:(UIButton *)sender {
exit(0);
}
// -------------------------------------------------------------------------------------------------------------------
- (IBAction)segmentedAction:(UISegmentedControl *)sender {
switch (sender.selectedSegmentIndex) {
case START:
NSLog(@"START");
self.running = YES;
if (operationQueue.operationCount < 1) {
[operationQueue addOperation:blockOperation]; // 2) *** fatal error on 2nd pass.
}
break;
case STOP:
NSLog(@"STOP");
self.running = NO;
break;
}
return;
}
@end
控制台输出:
BackgroundTask[3759:c07] STOP
BackgroundTask[3759:c07] START
BackgroundTask[3759:1303] {backgroundBlock} count = 0
BackgroundTask[3759:1303] {backgroundBlock} count = 1
BackgroundTask[3759:1303] {backgroundBlock} count = 2
BackgroundTask[3759:1303] {backgroundBlock} count = 3
BackgroundTask[3759:1303] {backgroundBlock} count = 4
BackgroundTask[3759:1303] {backgroundBlock} count = 5
BackgroundTask[3759:1303] {backgroundBlock} count = 6
BackgroundTask[3759:1303] {backgroundBlock} count = 7
BackgroundTask[3759:c07] STOP
BackgroundTask[3759:1303] {backgroundBlock} count = 8
最佳答案
我做了进一步的研究,发现
* 我必须重新创建每个“addOperation”的 NSBlockOperation 对象 *,因为 NSOperationQueue 拒绝 重新排队相同的 NSOperation 对象。
因此有以下解决方案:
- (IBAction)segmentedAction:(UISegmentedControl *)sender {
switch (sender.selectedSegmentIndex) {
case START:
NSLog(@"START");
self.running = YES;
blockOperation = nil;
[self buildBackgroundBlock];
blockOperation = [NSBlockOperation blockOperationWithBlock:backgroundBlock];
[operationQueue addOperation:blockOperation];
break;
case STOP:
NSLog(@"STOP");
self.running = NO;
break;
}
}
...至于编译器将 BOOL“isRunning”与静态“self”相关联:
Capturing 'self' strongly in this block is likely to lead to a retrain cycle.
所有对“ self ”的引用都应该通过薄弱环节。
- (void)buildBackgroundBlock {
static int k = 0;
BOOL myRunning = isRunning;
__weak ricViewController *weakObject = self;
backgroundBlock = ^{
while (myRunning) {
sleep(1);
if ([NSThread isMainThread]) {
NSLog(@"{backgroundBlock} *** Main Thread *** ***");
} else {
NSString *myString = [NSString stringWithFormat:@"{backgroundBlock} count = %i", k++];
NSLog(myString);
dispatch_async(dispatch_get_main_queue(), ^{
weakObject.dataLabel.text = [myString copy];
});
}
}
};
}
关于ios - NSOperationQueue 的 addOperation : operation is finished and cannot be enqueued?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16844806/
您好,我正在使用 Swift 构建应用程序。我需要按特定顺序处理通知。因此,我正在尝试使用 addOperations waitUntilFinished。 这是我做的: let oldify = N
注意: 这只是一个概念验证。 真正的后台任务将是不断请求原始数据的“HTTP Get”并通过主线程显示它;按需。 场景: 1)按需切换后台任务(循环)。 2) 后台任务每次迭代通知主线程UI。 3)
addOperation:waitUntilFinished 是否仅适用于 iOS 4.3 及更高版本?为什么我会收到此警告,我是不是错过了什么? 即使我收到这条警告消息,我的应用程序仍然可以正常运行
有时我必须在主线程上执行某些操作,建议将代码放置在 OperationQueue.main.addOperation 中。 其他时候,建议将代码编写在DispatchQueue.main.async内
我是一名优秀的程序员,十分优秀!