(ZAKTUALIZOWANY) jest to problem w pigułce: w iOS Chcę odczytać duży plik, zrobić na nim trochę przetwarzania (w tym konkretnym przypadku zakodować jako ciąg Base64() i zapisać do pliku tymczasowego na urządzeniu. I założyć NSInputStream do odczytu z pliku, a następnie wNSInputStream przestaje działać, czasami wyrzuca EXC_BAD_ACCESS
(void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
robię większość pracy. z jakiegoś powodu, czasem widzę NSInputStream prostu zatrzymuje Wiem, ponieważ mam linię
NSLog(@"stream %@ got event %x", stream, (unsigned)eventCode);
na początku (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
i czasami chciałbym tylko zobaczyć wyjście
stream <__NSCFInputStream: 0x1f020b00> got event 2
(co odpowiada przypadku NSStreamEventHasBytesAvailable) i wtedy nic później. Nie wydarzenie 10, które odpowiada NSStreamEventEndEncountered, a nie zdarzenie błędu, nic! Czasami nawet dostaję wyjątek EXC_BAD_ACCESS, który nie mam w tej chwili pojęcia jak debugować. Każda pomoc będzie doceniona.
Oto realizacja. Wszystko zaczyna się, kiedy uderzył w przycisk "Wyślij", który wyzwala:
- (IBAction)submit:(id)sender {
[p_spinner startAnimating];
[self performSelector: @selector(sendData)
withObject: nil
afterDelay: 0];
}
Oto sendData:
-(void)sendData{
...
_tempFilePath = ... ;
[[NSFileManager defaultManager] createFileAtPath:_tempFilePath contents:nil attributes:nil];
[self setUpStreamsForInputFile: [self.p_mediaURL path] outputFile:_tempFilePath];
[p_spinner stopAnimating];
//Pop back to previous VC
[self.navigationController popViewControllerAnimated:NO] ;
}
Oto setUpStreamsForInputFile nazywa powyżej:
- (void)setUpStreamsForInputFile:(NSString *)inpath outputFile:(NSString *)outpath {
self.p_iStream = [[NSInputStream alloc] initWithFileAtPath:inpath];
[p_iStream setDelegate:self];
[p_iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[p_iStream open];
}
Wreszcie, to gdzie występuje większość logiki:
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
NSLog(@"stream %@ got event %x", stream, (unsigned)eventCode);
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
if (stream == self.p_iStream){
if(!_tempMutableData) {
_tempMutableData = [NSMutableData data];
}
if ([_streamdata length]==0){ //we want to write to the buffer only when it has been emptied by the output stream
unsigned int buffer_len = 24000;//read in chunks of 24000
uint8_t buf[buffer_len];
unsigned int len = 0;
len = [p_iStream read:buf maxLength:buffer_len];
if(len) {
[_tempMutableData appendBytes:(const void *)buf length:len];
NSString* base64encData = [Base64 encodeBase64WithData:_tempMutableData];
_streamdata = [base64encData dataUsingEncoding:NSUTF8StringEncoding]; //encode the data as Base64 string
[_tempFileHandle writeData:_streamdata];//write the data
[_tempFileHandle seekToEndOfFile];// and move to the end
_tempMutableData = [NSMutableData data]; //reset mutable data buffer
_streamdata = [[NSData alloc] init]; //release the data buffer
}
}
}
break;
case NSStreamEventEndEncountered:
{
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
stream = nil;
//do some more stuff here...
...
break;
}
case NSStreamEventHasSpaceAvailable:
case NSStreamEventOpenCompleted:
case NSStreamEventNone:
{
...
}
}
case NSStreamEventErrorOccurred:{
...
}
}
}
Uwaga: kiedy opublikowałem to jako pierwsze, miałem złe wrażenie, że problem miał coś wspólnego z używaniem GCD. Zgodnie z odpowiedzią Roba poniżej usunąłem kod GCD, a problem nadal występuje.
Dzięki, LombaX. Aby upewnić się, że rozumiem, co mówisz. W moim oryginalnym pytaniu, byłem dipatching "sendData" do dispatch_async (dispatch_get_global_queue (0, 0) ... a następnie, gdy byłem konfiguracji strumienia do odczytu z pliku użyłem dispatch_async (dispatch_get_main_queue() ... You ' ponownie mówię, aby zachować zarówno i po prostu dodać [[NSRunLoop currentRunLoop] uruchomić]? Nie jestem pewien, że postępuję zgodnie z logiką, więc myślę, że lepiej upewnić się ... wielkie dzięki! – PeterD
jest to, co masz na myśli? '- (void) setUpStreamsForInputFile (NSString *) inpath oUTPUTFILE (NSString *) outpath { \t self.p_iStream = ... \t [p_iStream setDelegate Samodzielny]; \t dispatch_async (dispatch_get_main_queue()^{ \t \t [p_iStream scheduleInRunLoop [ NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode]; \t \t [p_iStream otwórz]; \t \t ** [[NSRunLoop currentRunLoop] run]; ** \t}); } ' – PeterD
A to: ' - (IBAction) przesłać: (identyfikator) nadawca { [p_spinner startAnimating]; dispatch_queue_t queue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async (kolejka,^{ [self sendData]; ** [[NSRunLoop currentRunLoop] run]; **}); } ' } Przepraszamy za bycie rozwartym .. :) – PeterD