在上下文中要求以下两个问题来维护NSOperationQueue和NSInvocationOperation.
由于我使用此概念下载多个视频,如何在完成下载视频后从NSOperationQueue中删除/释放添加的NSInvocationOperation?
而且,如果我想在下载过程中停止下载特定视频,我该怎么办?
我正在尝试构建一个下载管理器类,它将所有异步下载(每个操作都有自己的线程)操作打包到 NSOperation 子类中,以便稍后将它们添加到 NSOperationQueue 中。下载管理器类(单例)还公开了一些方法来处理队列并取消符合某些要求的操作。
这些是开始创建类集群(抽象工厂)的步骤,该类集群为不同类型的常见操作(上传、下载、解析等)返回不同类型的 NSOperation。
该类似乎可以很好地处理下载操作,但如果在这些操作中间我调用取消操作的方法,则该操作会成功取消,但应用程序会在稍后的几个操作中崩溃。如果我不取消任何操作,一切都会正常。所有操作均使用 KVO 进行观察。删除操作的方法如下所示:
- (void) cancelDownloadOperationWithID:(NSString *)aUUID{
@synchronized(self){
[self.dowloadQueue setSuspended:YES]; //downloadQueue is an NSOperationQueue
NSArray * downloadOperations = [self.dowloadQueue operations];
NSPredicate * aPredicate = [NSPredicate predicateWithFormat:@"SELF.connectionID == %@",aUUID]; //SELF is the signleton instance of the download manager
NSArray * filteredArray = [downloadOperations filteredArrayUsingPredicate:aPredicate];
if ([filteredArray count]==0) {
[self.dowloadQueue setSuspended:NO];
return;
}
[filteredArray makeObjectsPerformSelector:@selector(cancel)];
NSLog(@"Cancelled %d operations",[filteredArray count]);
[self.dowloadQueue setSuspended:NO];
}
}
Run Code Online (Sandbox Code Playgroud)
崩溃日志非常难以理解,但是是一个 BAD_EXC_ACCESS (可能是僵尸),请注意我处于 ARC 下。
0x00a90ea8 <+0393> jle 0xa90d9f <____NSOQSchedule_block_invoke_0+128>
0x00a90eae <+0399> …Run Code Online (Sandbox Code Playgroud) 注意:
这只是一个概念验证。
真正的后台任务是不断请求原始数据的“HTTP Get”并通过主线程显示;一经请求。
场景:
1)按需切换后台任务(循环)。
2) 后台任务在每次迭代时通知主线程 UI。
3) 只有一 (1) 个块操作在队列中运行。
Modus Operandus
1) 使用 NSBlockOperation 来包含后台代码。
2)使用区域BOOL来切换循环;通过 IBAction。
问题
1) 编译器将 BOOL 'isRunning' 标记为强链接:
在此块中强烈捕获“自我”可能会导致保留循环。
2)在尝试添加块操作之前,我检查了队列中是否有任何操作。
但我总是收到以下错误:
-[NSOperationQueue addOperation:]: 操作完成,不能入队
除了上述问题之外,这种概念验证似乎正在发挥作用。
问题:
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 …Run Code Online (Sandbox Code Playgroud) 我们创建了一个操作框架来添加一些在基类中没有的功能(例如跟踪成功/失败)。父操作通常是非并发的,可能只是为了管理子操作而存在。通常并发的子操作(异步下载 xml 和媒体)。
当我们在 iOS 7 上运行我们的应用程序时,将一些操作添加到操作队列中,大约有 3/4 的操作完成,然后应用程序似乎挂起。
当我在调试器中暂停应用程序,并检查队列中的操作 (sOpQueue.operations) 时,其中许多已准备好运行(isReady 返回 TRUE),但显然它们都没有执行(isExecuting 返回 FALSE,而我看不到任何线程上运行的任何操作的证据)。
这是 iOS 7 的新问题。
当我增加或减少并发操作的数量时,行为似乎没有改变。
有没有人对如何确定未启动就绪操作的原因有任何建议?
谢谢,查克
我有一个类,它是NSOperationQueue. 它允许使用块对网络请求进行排队。目前,请求是一个接一个执行的,但这种情况将来可能会改变。
这是 MyRequestsQueue 类的代码:
@interface MyRequestsQueue ()
@property(nonatomic, strong) NSOperationQueue* queue;
@end
@implementation MyRequestsQueue
-(instancetype)init
{
self = [super init];
if(!self) {
return nil;
}
self.queue = [[NSOperationQueue new] autorelease];
self.queue.maxConcurrentOperationCount = 1;
return self;
}
-(void)addRequestBlock:(void (^)())request
{
NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:request];
[self.queue addOperation:operation];
}
@end
Run Code Online (Sandbox Code Playgroud)
一般来说,我知道如何使用 XCTest 对异步代码进行单元测试。但现在我想添加一个单元测试来MyRequestsQueue检查队列当时是否只执行一个操作。或者甚至更好 - 测试当前正在执行的操作的数量不大于maxConcurrentOperationCount。我试图观察operationCount的属性self.queue,但文档说我不应该依赖它。我怎样才能实现它?
编辑:我的测试使用以下模式:
@interface MessageRequestQueueTest : XCTestCase
@property(nonatomic, strong) MessageRequestsQueue* reuqestQueue;
@property(nonatomic, assign) NSInteger finishedRequestsCounter;
@end …Run Code Online (Sandbox Code Playgroud) 基本上,如果我添加到队列的操作在某个超时后没有响应,我想执行取消:
NSOperationQueue * queue = ...
[self.queue addOperationWithBlock:^{
// my block...
} timeoutInSeconds:5.0 hasTimedOutWithBlock:^{
// called after 5.0, operation should be canceled at the end
}];
Run Code Online (Sandbox Code Playgroud)
多谢你们 !
我有以下代码:
func testFunc(completion: (Bool) -> Void) {
let queue = NSOperationQueue()
queue.maxConcurrentOperationCount = 1
for i in 1...3 {
queue.addOperationWithBlock{
Alamofire.request(.GET, "https://httpbin.org/get").responseJSON { response in
switch (response.result){
case .Failure:
print("error")
break;
case .Success:
print("i = \(i)")
}
}
}
//queue.addOperationAfterLast(operation)
}
queue.waitUntilAllOperationsAreFinished()
print("finished")
}
Run Code Online (Sandbox Code Playgroud)
输出是:
finished
i = 3
i = 1
i = 2
Run Code Online (Sandbox Code Playgroud)
但我希望以下内容:
i = 3
i = 1
i = 2
finished
Run Code Online (Sandbox Code Playgroud)
那么,为什么queue.waitUntilAllOperationsAreFinished()不等待?
我正在尝试实现NSOperationQueue完成swift 3中的所有任务操作.我创建了一个下面的演示代码,它正在按照我的期望工作.
func downloadTopStroiesDetails(){
let operationQueue: OperationQueue = OperationQueue()
let operation1 = BlockOperation() {
print("BlockOperation1")
for id in 0...5{
operationQueue.addOperation(downloadArticle(index: id))
}
let operation2 = BlockOperation() {
print("BlockOperation2")
}
operationQueue.addOperation(operation2)
}
operationQueue.addOperation(operation1)
}
func downloadArticle(index:Int) -> Operation {
let operation: Operation = BlockOperation { () -> Void in
print(index)
}
return operation
}
downloadTopStroiesDetails() // start calling
Run Code Online (Sandbox Code Playgroud)
输出:
BlockOperation1
0
1
2
3
4
5
BlockOperation2
Run Code Online (Sandbox Code Playgroud)
但是当我在下载文章中使用Alamofire调用Web API时,方法输出是不同的.
func downloadArticle(index:Int) -> Operation {
let operation = BlockOperation(block: {
RequestManager.networkManager.fetchFromNetworkwithID(articleid: index) …Run Code Online (Sandbox Code Playgroud) 在了解了Swift 的捕获列表以及如何使用它来避免保留循环之后,我不禁注意到一些令人费解的事情OperationQueue:它不需要[weak self]或 来[unowned self]防止内存泄漏。
class SomeManager {
let queue = OperationQueue()
let cache: NSCache = { () -> NSCache<AnyObject, AnyObject> in
let cache = NSCache<AnyObject, AnyObject>()
cache.name = "huaTham.TestOperationQueueRetainCycle.someManager.cache"
cache.countLimit = 16
return cache
}()
func addTask(a: Int) {
queue.addOperation { // "[unowned self] in" not needed?
self.cache.setObject(a as AnyObject, forKey: a as AnyObject)
print("hello \(a)")
}
}
}
class ViewController: UIViewController {
var someM: SomeManager? = SomeManager()
override func viewDidLoad() …Run Code Online (Sandbox Code Playgroud) memory-leaks nsoperationqueue automatic-ref-counting retain-cycle swift
在我的项目中,我需要将数据发送到服务器,为此我使用以下代码来完成任务:
- (void)sendJSONToServer:(NSString *) jsonString
{
// Create a new NSOperationQueue instance.
operationQueue = [NSOperationQueue new];
//
// Create a new NSOperation object using the NSInvocationOperation subclass to run the operationQueueTask method
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(operationQueueTask:)
object:jsonString];
// Add the operation to the queue and let it to be executed.
[operationQueue addOperation:operation];
}//End of sendJSONToServer method
-(void) operationQueueTask:(NSString *) jsonString
{
//NSOperationQueue *remoteResultQueue = [[NSOperationQueue alloc] init];
dispatch_queue_t myQueue = dispatch_queue_create("SERVER_QUEUE",NULL);
dispatch_async(myQueue, ^{
// Performing long running …Run Code Online (Sandbox Code Playgroud) nsoperationqueue ×10
ios ×8
nsoperation ×6
iphone ×3
objective-c ×3
swift ×3
asynchronous ×1
cloudkit ×1
download ×1
memory-leaks ×1
nsinvocation ×1
retain-cycle ×1
unit-testing ×1
xctest ×1