ios – NSInputStream停止运行,有时会抛出EXC_BAD_ACCESS

ios – NSInputStream停止运行,有时会抛出EXC_BAD_ACCESS,第1张

概述(更新)这是一个简单的问题:在iOS中,我想要读取一个大文件,对它进行一些处理(在这种特殊情况下编码为Base64 string()并保存到设备上的临时文件,我设置一个从文件读取的NSInputStream,然后在 (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode 我在做大部分的工作.由于某些原因,有时我可以看 (更新)这是一个简单的问题:在iOS中,我想要读取一个大文件,对它进行一些处理(在这种特殊情况下编码为Base64 string()并保存到设备上的临时文件,我设置一个从文件读取的NSinputStream,然后在
(voID)stream:(Nsstream *)stream handleEvent:(NsstreamEvent)eventCode

我在做大部分的工作.由于某些原因,有时我可以看到NSinputStream刚停止工作.我知道,因为我有一条线

NSLog(@"stream %@ got event %x",stream,(unsigned)eventCode);

在(voID)stream:(Nsstream *)的开头处理streamEvent:(NsstreamEvent)eventCode,有时候我会看到输出

stream <__NSCFinputStream: 0x1f020b00> got event 2

(对应于事件NsstreamEventHasBytesAvailable),然后再没有.不是事件10,对应于NsstreamEventEndEnmitted,不是错误事件,没有!还有时候我甚至得到一个EXC_BAD_ACCESS异常,我现在不知道如何调试.任何帮助将不胜感激.

这是实现.当我点击“提交”按钮时,一切都会启动,这会触发:

- (IBAction)submit:(ID)sender {         [p_spinner startAnimating];        [self performSelector: @selector(sendData)           withObject: nil           afterDelay: 0];   }

这里是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 prev@R_301_6928@s VC    [self.navigationController popVIEwControllerAnimated:NO] ;}

这里是上面提到的setUpStreamsForinputfile:

- (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];   }

最后,这是大多数逻辑发生的地方:

- (voID)stream:(Nsstream *)stream handleEvent:(NsstreamEvent)eventCode {    NSLog(@"stream %@ got event %x",(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:{            ...        }    }}

注意:当我第一次发布时,我的错误印象是这个问题与使用GCD有关.根据Rob在下面的回答,我删除了GCD代码,问题依然存在.

解决方法 首先:在你的原始代码中,你没有使用后台线程,而是主线程(dispatch_async,但是在主队列中).

当您安排NSinputStream运行在默认的runloop(因此,主线程的runloop)时,主线程处于默认模式(NSDefaultRunLoopMode)时会收到事件.

但是,如果您检查,在某些情况下(例如,在UIScrollVIEw滚动和其他UI更新期间),默认运行环境更改模式.当主runloop处于与NSDefaultRunLoopMode不同的模式时,不会收到您的事件.

您的旧代码与dispatch_async几乎相当(但是在主线程上移动UI更新).您只需添加一些更改:

>在后台调度,这样的东西:

dispatch_queue_t queue = dispatch_get_global_queue(disPATCH_QUEUE_PRIORITY_DEFAulT,0); dispatch_async(queue,^{      // your background code     //end of your code     [[NSRunLoop currentRunLoop] run]; // start a run loop,look at the next point});

>在该线程上启动一个运行循环.必须使用此代码在调度异步调用的最后一行(最后一行)完成此 *** 作

[[NSRunLoop currentRunLoop] run]; // note: this method never returns,so it must be THE LAST liNE of your dispatch

尝试让我知道

编辑 – 添加示例代码:

为了更清楚,我复制粘贴您的原始代码更新:

- (voID)setUpStreamsForinputfile:(Nsstring *)inpath outputfile:(Nsstring *)outpath  {    self.p_iStream = [[NSinputStream alloc] initWithfileAtPath:inpath];    [p_iStream setDelegate:self];    // here: change the queue type and use a background queue (you can change priority)    dispatch_queue_t queue = dispatch_get_global_queue(disPATCH_QUEUE_PRIORITY_DEFAulT,0);    dispatch_async(queue,^ {        [p_iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]                       forMode:NSDefaultRunLoopMode];        [p_iStream open];        // here: start the loop        [[NSRunLoop currentRunLoop] run];        // note: all code below this line won't be executed,because the above method NEVER returns.    });    }

进行此修改后,您的

- (voID)stream:(Nsstream *)stream handleEvent:(NsstreamEvent)eventCode {}

方法,将在您启动运行循环的同一线程上调用一个后台线程:如果需要更新UI,重要的是再次发送到主线程.

额外信息:

在我的代码中,我在随机的后台队列中使用dispatch_async(在一个可用的后台线程上调度你的代码,或者如果需要的话可以启动一个新的代码),所有这些都是“自动的”).如果您愿意,您可以启动自己的线程,而不是使用dispatch异步.

此外,在发送“运行”消息之前,我不检查一个运行循环是否已经运行(但是您可以使用currentMode方法检查它,查看NSRunLoop参考以获取更多信息).它不应该是必要的,因为每个线程只有一个关联的NSRunLoop实例,所以发送另一个运行(如果已经运行)没有什么不好:-)

你甚至可以避免直接使用runLoops,并使用dispatch_source切换到一个完整的GCD方法,但是我从未直接使用它,所以我现在不能给你一个“好的示例代码”

总结

以上是内存溢出为你收集整理的ios – NSInputStream停止运行,有时会抛出EXC_BAD_ACCESS全部内容,希望文章能够帮你解决ios – NSInputStream停止运行,有时会抛出EXC_BAD_ACCESS所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/1095209.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-28
下一篇2022-05-28

发表评论

登录后才能评论

评论列表(0条)

    保存