- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我有一个应用程序目前使用 NSURLConnection
进行绝大多数网络。我想搬到 NSURLSession
因为 Apple 告诉我这是要走的路。
我的应用只是通过 + (NSData *)sendSynchronousRequest:(NSURLRequest *)request returnedResponse:(NSURLResponse **)response error:(NSError 的方式使用
类方法。我在运行在 NSURLConnection
的同步版本**)errorNSOperationQueue
上的 NSBlockOperation
中执行此操作,因此我不会不必要地阻塞主队列。以这种方式做事的一大优势是我可以使操作相互依赖。例如,我可以让请求数据的任务依赖于登录任务的完成。
我没有在 NSURLSession
中看到任何对同步操作的支持。我能找到的所有文章都 mock 我甚至考虑同步使用它,并且我是一个阻塞线程的可怕人。美好的。但我认为没有办法让 NSURLSessionTask
相互依赖。有没有办法做到这一点?
或者有没有描述我将如何以不同的方式做这样的事情?
最佳答案
对同步网络请求最严厉的批评是留给那些从主队列执行的人(因为我们知道永远不应该阻塞主队列)。但是你是在你自己的后台队列上做的,它解决了同步请求中最严重的问题。但是您正在失去异步技术提供的一些出色功能(例如,如果需要,可以取消请求)。
我将在下面回答您的问题(如何使 NSURLSessionDataTask
同步运行),但我真的鼓励您接受异步模式而不是反对它们。我建议重构您的代码以使用异步模式。具体来说,如果一个任务依赖于另一个任务,只需将依赖任务的启动放在前一个任务的完成处理程序中即可。
如果您在该转换中遇到问题,请发布另一个 Stack Overflow 问题,向我们展示您的尝试,我们可以尝试帮助您。
如果您想使异步操作同步,一种常见的模式是使用分派(dispatch)信号量,以便启动异步进程的线程可以在继续之前等待来自异步操作完成 block 的信号。永远不要从主队列执行此操作,但如果您是从某个后台队列执行此操作,这可能是一种有用的模式。
您可以使用以下方法创建信号量:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
然后您可以让异步进程的完成 block 向信号量发出信号:
dispatch_semaphore_signal(semaphore);
然后您可以让代码在完成 block 之外(但仍在后台队列中,而不是主队列中)等待该信号:
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
因此,使用 NSURLSessionDataTask
,将所有内容放在一起,可能看起来像:
[queue addOperationWithBlock:^{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSURLSession *session = [NSURLSession sharedSession]; // or create your own session with your own NSURLSessionConfiguration
NSURLSessionTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data) {
// do whatever you want with the data here
} else {
NSLog(@"error = %@", error);
}
dispatch_semaphore_signal(semaphore);
}];
[task resume];
// but have the thread wait until the task is done
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// now carry on with other stuff contingent upon what you did above
]);
使用 NSURLConnection
(现已弃用),您必须跳过一些环节才能从后台队列发起请求,但 NSURLSession
可以优雅地处理它。
话虽如此,使用这样的 block 操作意味着操作不会响应取消事件(至少在它们运行时)。因此,我通常会使用 block 操作来避免这种信号量技术,而只是将数据任务包装在异步 NSOperation
子类中。然后,您可以享受运营带来的好处,但您也可以将其取消。这是更多的工作,但更好的模式。
例如:
//
// DataTaskOperation.h
//
// Created by Robert Ryan on 12/12/15.
// Copyright © 2015 Robert Ryan. All rights reserved.
//
@import Foundation;
#import "AsynchronousOperation.h"
NS_ASSUME_NONNULL_BEGIN
@interface DataTaskOperation : AsynchronousOperation
/// Creates a operation that retrieves the contents of a URL based on the specified URL request object, and calls a handler upon completion.
///
/// @param request A NSURLRequest object that provides the URL, cache policy, request type, body data or body stream, and so on.
/// @param dataTaskCompletionHandler The completion handler to call when the load request is complete. This handler is executed on the delegate queue. This completion handler takes the following parameters:
///
/// @returns The new session data operation.
- (instancetype)initWithRequest:(NSURLRequest *)request dataTaskCompletionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))dataTaskCompletionHandler;
/// Creates a operation that retrieves the contents of a URL based on the specified URL request object, and calls a handler upon completion.
///
/// @param url A NSURL object that provides the URL, cache policy, request type, body data or body stream, and so on.
/// @param dataTaskCompletionHandler The completion handler to call when the load request is complete. This handler is executed on the delegate queue. This completion handler takes the following parameters:
///
/// @returns The new session data operation.
- (instancetype)initWithURL:(NSURL *)url dataTaskCompletionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))dataTaskCompletionHandler;
@end
NS_ASSUME_NONNULL_END
和
//
// DataTaskOperation.m
//
// Created by Robert Ryan on 12/12/15.
// Copyright © 2015 Robert Ryan. All rights reserved.
//
#import "DataTaskOperation.h"
@interface DataTaskOperation ()
@property (nonatomic, strong) NSURLRequest *request;
@property (nonatomic, weak) NSURLSessionTask *task;
@property (nonatomic, copy) void (^dataTaskCompletionHandler)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error);
@end
@implementation DataTaskOperation
- (instancetype)initWithRequest:(NSURLRequest *)request dataTaskCompletionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))dataTaskCompletionHandler {
self = [super init];
if (self) {
self.request = request;
self.dataTaskCompletionHandler = dataTaskCompletionHandler;
}
return self;
}
- (instancetype)initWithURL:(NSURL *)url dataTaskCompletionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))dataTaskCompletionHandler {
NSURLRequest *request = [NSURLRequest requestWithURL:url];
return [self initWithRequest:request dataTaskCompletionHandler:dataTaskCompletionHandler];
}
- (void)main {
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:self.request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
self.dataTaskCompletionHandler(data, response, error);
[self completeOperation];
}];
[task resume];
self.task = task;
}
- (void)completeOperation {
self.dataTaskCompletionHandler = nil;
[super completeOperation];
}
- (void)cancel {
[self.task cancel];
[super cancel];
}
@end
地点:
//
// AsynchronousOperation.h
//
@import Foundation;
@interface AsynchronousOperation : NSOperation
/// Complete the asynchronous operation.
///
/// This also triggers the necessary KVO to support asynchronous operations.
- (void)completeOperation;
@end
和
//
// AsynchronousOperation.m
//
#import "AsynchronousOperation.h"
@interface AsynchronousOperation ()
@property (nonatomic, getter = isFinished, readwrite) BOOL finished;
@property (nonatomic, getter = isExecuting, readwrite) BOOL executing;
@end
@implementation AsynchronousOperation
@synthesize finished = _finished;
@synthesize executing = _executing;
- (instancetype)init {
self = [super init];
if (self) {
_finished = NO;
_executing = NO;
}
return self;
}
- (void)start {
if ([self isCancelled]) {
self.finished = YES;
return;
}
self.executing = YES;
[self main];
}
- (void)completeOperation {
self.executing = NO;
self.finished = YES;
}
#pragma mark - NSOperation methods
- (BOOL)isAsynchronous {
return YES;
}
- (BOOL)isExecuting {
@synchronized(self) {
return _executing;
}
}
- (BOOL)isFinished {
@synchronized(self) {
return _finished;
}
}
- (void)setExecuting:(BOOL)executing {
@synchronized(self) {
if (_executing != executing) {
[self willChangeValueForKey:@"isExecuting"];
_executing = executing;
[self didChangeValueForKey:@"isExecuting"];
}
}
}
- (void)setFinished:(BOOL)finished {
@synchronized(self) {
if (_finished != finished) {
[self willChangeValueForKey:@"isFinished"];
_finished = finished;
[self didChangeValueForKey:@"isFinished"];
}
}
}
@end
关于ios - 带有 NSBlockOperation 和队列的 NSURLSession,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21198404/
为了避免在 Objective-C 中使用 NSBlockOperation 时发生内存泄漏,我们必须将变量声明为 weak 以便能够引用 block 内的 block 操作(如果需要则取消),通常如
我创建了一个实现一些方法的类。这些方法由另一个类调用,并通过 NSBlockOperation 进行管理。 我的 NSBlockOperation 工作正常,我在尝试计算变量时遇到问题: EXC_BA
我正在学习 NSOperations 和 NSOperationQueue。 我有一组 NSBlockOperation:“UPLOAD”和“DELETE”。删除必须在执行前等待上传完成。 我希望发生
在检查我的代码时,我发现在很多地方我都假设调用 [NSBlockOperationInstance start]; 将在主线程上启动此操作。我不知道我为什么这么想,但无论如何我都不应该这么确定。我检查
我正在进入 NSBlockOperation 并且我有一些问题。值得注意的是,documentation对于 addExecutionBlock 说: Discussion The specified
由于我目前正在处理 Web 服务调用和数据库检索,所以我偶然发现了 NSBlockOperation 未启动的问题。 但是,首先要稍微解释一下。主要目标是拥有一个由以下操作组成的操作队列: 操作 #1
我在引用 block 本身内的“NSBlockOperation”时遇到麻烦。我需要检查操作是否被取消,并且似乎在启用 ARC 的项目中运行时,对“searchOperation”的任何访问都会泄漏。
我正在尝试在后台线程上发出网络请求,并且我决定使用 NSBlockOperations。我正在使用 ADNKit处理我的获取请求。这是代码: - (void)reloadPosts { dis
我扩展了 NSOperationQueue 以允许添加带有特定 NSString 作为标识符的 NSBlockOperation。 标识符值保存在用作注册表的 NSMutableArray 中。这就是
我有一个长时间运行的循环,我想使用 NSOperation 在后台运行。我想使用一个 block : NSBlockOperation *operation = [NSBlockOperation b
我有一个问题。我有以下代码: NSBlockOperation *op=[NSBlockOperation blockOperationWithBlock:^{ [[ClassA sh
我有一个 UITableView,其中每个部分都包含一行,每一行都包含一个 UICollectionView。 UITableView 是数据源并委托(delegate)给 Core Data 数据库
大家好,我很沮丧,因为我想改进代码,但我没有得到好的结果,这是我的代码 NSBlockOperation *blockOperation1 = [NSBlockOperation blockOpera
我必须从我的 RestAPI 同步一堆信息。我必须进行 6 次 RestAPI 调用才能完成工作。我用 Blocks 设计了 API 调用,如果有则返回 NSError。其中 3 个调用应该嵌套执
在我的项目中,我使用 NSBlockOperation 在后台线程上运行一个操作: var operationQueue = NSOperationQueue() var iop = NSBlockO
通常,当您创建一个 NSOperation 子类时,您负责在 -main 方法中创建和释放一个 NSAutoreleasePool。 当你使用 NSBlockOperation 时,你需要在 bloc
Foundation Framework 中共有三个操作类(NSOperation、NSInvocationOperation 和NSBlockOperation)。 我已经阅读了 concurren
我有一个应用程序目前使用 NSURLConnection 进行绝大多数网络。我想搬到 NSURLSession 因为 Apple 告诉我这是要走的路。 我的应用只是通过 + (NSData *)sen
我正在调试我的应用程序的一个有趣问题。 该应用程序针对iOS6.1,并且使用ARC。这是一些背景,因为它太大,无法复制粘贴到 SO 中。 有一个 Dashboard 类,它有一个 subview Co
我在使用 NSBlockOperation 并尝试访问 EKEventStore 时遇到问题。这是我的代码: 这段代码异步运行 NSBlockOperation *wordsOp =
我是一名优秀的程序员,十分优秀!