我在這裏遇到了一些問題。我正在開發一個讀取文件並在UITableView中顯示其內容的應用程序。我最近意識到文件可能會變得非常大,我需要對文件的實際讀取進行異步編碼。我的項目已經很大,今天我設法將我已經擁有的代碼包裝在NSOperation中。使用NSOperation在NSOperationQueue中運行並行代碼
我所做的是我的解析器(打開並閱讀我的文件)現在在NSOperation中調用。就像那樣:
@implementation ReadPcapOperation
@synthesize parser =_parser;
- (id) initWithURL:(NSURL *)url linkedTo:(PacketFlowViewController *)packetController
{
self = [super init];
if (self) {
_parser = [[PcapParser alloc] initWithURL:url linkedTo:packetController];
}
return self;
}
- (void)main {
// a lengthy operation
@autoreleasepool {
if (self.isCancelled)
return;
[_parser read];
}
}
@end
我只給你這裏的實現,沒有什麼重要的.h文件。此子類的NSOperation被稱爲的NSOperation內:
_queue = [NSOperationQueue new];
_queue.name = @"File Parsing Queue";
_queue.maxConcurrentOperationCount = 1;
[_queue addOperation:_readFileOperation];
_readFileOperation是上述ReadPcapOperation的一個實例。
現在,當我測試我的代碼時,仍然沒有區別,當我打開一個文件時,UI仍然被阻塞,而文件內容被加載到我的UITableView中。我有這個條件測試:
[NSThread isMainThread]
該測試在主返回NO從ReadPcapOperation,這是很好的,正是我需要的。但是這個測試返回YES當我把它放在方法「read」中時,從ReadPcapOperation發送到main裏面的對象!所以我的整個代碼仍然在mainthread上運行,並阻止了我的UI。
我在這裏錯過什麼,夥計們?
讓我知道如果你需要更多的解釋!
編輯:
這裏是很奇怪:我會發佈一個本應在後臺線程中執行我的代碼的一部分。
- (void) read
{
if ([NSThread isMainThread])
NSLog(@"read: IT S MAIN THREAD");
else
NSLog(@"read: IT S NOT MAIN THREAD");
[_fileStream open];
}
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode)
{
case NSStreamEventOpenCompleted:
{
//We read the pcap file header
[self readGlobalHeader];
[self readNextPacket];
break;
}
case NSStreamEventHasBytesAvailable:
{
//We read all packets
[self readNextPacket];
break;
}
case NSStreamEventNone:
{
break;
}
case NSStreamEventHasSpaceAvailable:
{
break;
}
case NSStreamEventEndEncountered:
{
NSLog(@"End encountered !");
[_fileStream close];
[_fileStream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
//_fileStream = nil;
break;
}
case NSStreamEventErrorOccurred:
{
NSError *theError = [stream streamError];
NSLog(@"Error %i stream event occured. Domain : %@.", theError.code, theError.domain);
[stream close];
break;
}
}
}
- (void) readGlobalHeader
{
if ([NSThread isMainThread])
NSLog(@"readGlobalHeader: IT S MAIN THREAD");
else
NSLog(@"readGlobalHeader: IT S NOT MAIN THREAD");
int sizeOfGlobalHeader = 24;
在這裏你可以看到我直接從NSOperation調用的讀取方法。那裏的日誌說:「沒有主線」。到現在爲止還挺好。讀取打開NSInputStreamObject,然後委託將調用「handleEvent」,並在此刻讀取字節。當我調用「readGlobalHeader」並讀取我的文件的第一個字節時,日誌是「MAIN THREAD」。它不應該在後臺線程中嗎?我真的迷失了!
可能是什麼重要的是要注意的是,當我初始化流,caling前「讀」我將它設置了這行代碼(我不知道它的原因):
[_fileStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
編輯2: 這是斷點後的回溯。行爲就像我上面描述的那樣。 (沒有足夠多的聲譽,發表圖片)
Breakpoint at the read method Breakpoint after the stream is open
'read'方法做了什麼,你在哪裏登錄它是否在主線程上?在返回** YES **的日誌語句中設置一個斷點併發布回溯。 – bbum
read是一種簡單地向NSInputStream對象發送「open」的方法。我使用NSInputStream來讀取我的文件。一旦流打開,我解析文件,讀取字節後的字節和類似的東西。我編輯了我的文章,看看吧! – Starscream