Ответ 1
Несколько подходов:
-
Запланируйте
NSURLConnection
в цикле основного запуска, используя параметрstartImmediately
NO
, установите цикл выполнения и только тогда вы должны начать соединение, например:urlConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:NO]; [urlConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; [urlConnection start];
-
Создайте выделенный поток для соединения и запланируйте соединение в цикле запуска, который вы создаете для этого потока. См.
AFURLConnectionOperation.m
в AFNetworking источник для примера. -
Фактически используйте AFNetworking, который дает вам операции
NSOperation
, которые вы можете добавить в свою очередь, и берет на себя заботу этого цикла для вас.
Итак, AFNetworking делает что-то вроде:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool {
[[NSThread currentThread] setName:@"NetworkingThread"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self
selector:@selector(networkRequestThreadEntryPoint:)
object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
Итак, я делаю что-то вроде следующего. Сначала у меня есть несколько частных свойств:
@property (nonatomic, readwrite, getter = isExecuting) BOOL executing;
@property (nonatomic, readwrite, getter = isFinished) BOOL finished;
@property (nonatomic, weak) NSURLConnection *connection;
Затем сетевая операция может сделать что-то вроде:
@synthesize executing = _executing;
@synthesize finished = _finished;
- (instancetype)init {
self = [super init];
if (self) {
_executing = NO;
_finished = NO;
}
return self;
}
- (void)start {
if (self.isCancelled) {
[self completeOperation];
return;
}
self.executing = YES;
[self performSelector:@selector(startInNetworkRequestThread)
onThread:[[self class] networkRequestThread]
withObject:nil
waitUntilDone:NO];
}
- (void)startInNetworkRequestThread {
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:self.request
delegate:self
startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
self.connection = connection;
}
- (void)completeOperation {
self.executing = NO;
self.finished = YES;
}
- (void)setFinished:(BOOL)finished {
if (finished != _finished) {
[self willChangeValueForKey:@"isFinished"];
_finished = finished;
[self didChangeValueForKey:@"isFinished"];
}
}
- (void)setExecuting:(BOOL)executing {
if (executing != _executing) {
[self willChangeValueForKey:@"isExecuting"];
_executing = executing;
[self didChangeValueForKey:@"isExecuting"];
}
}
- (BOOL)isConcurrent {
return YES;
}
- (BOOL)isAsynchronous {
return YES;
}
// all of my NSURLConnectionDataDelegate stuff here, for example, upon completion:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// I call the appropriate completion blocks here, do cleanup, etc. and then, when done:
[self completeOperation];
}