本文介绍了带有上传流的NSURLSession-子类化NSInputStream-com.apple.NSURLConnectionLoader异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些使用某些C ++流接口的多平台库.我必须使用此流接口通过NSURLSession上传数据.我的实现应在OS X和iOS上运行(当前我正在OS X上进行测试)

I have some multiplatform library which is using some C++ stream interface. I have to use this stream interface to upload data by NSURLSession. My implementation should work on OS X and iOS (currently I'm testing on OS X)

任务看起来很简单,我确信我会很快实现这一点.我已经配置了NSURLSession,如果我将NSURLRequest与简单的NSData一起使用,则可以正常工作.我正在尝试使用像这样的流:

Task looks quite simple and I was sure I will implement this quite fast.I have configured NSURLSession which is working fine if I'm using NSURLRequest with simple NSData.I'm trying to use stream like this:

        NSURLSessionDataTask *dataTask = [m_Private.session uploadTaskWithStreamedRequest: request];
        HTTPDownoadTaskProxy *dataTaskProxy = [HTTPDownoadTaskProxy new];
        // store data to properly handle delegate
        dataTaskProxy.coreTask = dataTask;
        dataTaskProxy.cppRequest= req;
        dataTaskProxy.cppResponseHandler = handler;
        dataTaskProxy.cppErrorHandler = errorHandler;

        m_Private.streamedDataTasks[dataTask] = dataTaskProxy;

        [dataTask resume];

到目前为止,一切都很好.根据uploadTaskWithStreamedRequest的文档,我应该收到代表的通知,并且确实收到了它:

So far so good. According to documentation of uploadTaskWithStreamedRequest I should receive notification from delegate and I do receive it:

- (void)URLSession: (NSURLSession *)session
              task: (NSURLSessionTask *)task
 needNewBodyStream: (void (^)(NSInputStream *bodyStream))completionHandler
{
    HTTPDownoadTaskProxy *proxyTask = self.streamedDataTasks[task];
    CppInputStreamWrapper *objcInputStream = [[CppInputStreamWrapper alloc] initWithCppInputStream:proxyTask.cppRequest.GetDataStream()];
    completionHandler(objcInputStream);
}

现在,我应该以NSInputStream的子类(在我的情况下为CppInputStreamWrapper)接收呼叫,这也很简单:

Now I should receive calls in subclass of NSInputStream which is in my case CppInputStreamWrapper, and also it is quite simple:

@implementation CppInputStreamWrapper

- (void)dealloc {
    NSLog(@"%s", __PRETTY_FUNCTION__);
}

- (instancetype)initWithCppInputStream: (const std::tr1::shared_ptr<IInputStream>&) cppInputStream
{
    if (self = [super init]) {
        _cppInputStream = cppInputStream;
    }
    return self;
}

#pragma mark - overrides for NSInputStream
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len {
    return (NSInteger)self.cppInputStream->Read(buffer, len);
}

- (BOOL)getBuffer:(uint8_t **)buffer length:(NSUInteger *)len {
    return NO;
}

- (BOOL)hasBytesAvailable {
    return !self.cppInputStream->IsEOF();
}

#pragma mark - this methods are need to be overridden to make stream working
- (void)scheduleInRunLoop:(__unused NSRunLoop *)aRunLoop
                  forMode:(__unused NSString *)mode
{}

- (void)removeFromRunLoop:(__unused NSRunLoop *)aRunLoop
                  forMode:(__unused NSString *)mode
{}

#pragma mark - Undocumented CFReadStream Bridged Methods
- (void)_scheduleInCFRunLoop:(__unused CFRunLoopRef)aRunLoop
                     forMode:(__unused CFStringRef)aMode
{}

- (void)_unscheduleFromCFRunLoop:(__unused CFRunLoopRef)aRunLoop
                         forMode:(__unused CFStringRef)aMode
{}

- (BOOL)_setCFClientFlags:(__unused CFOptionFlags)inFlags
                 callback:(__unused CFReadStreamClientCallBack)inCallback
                  context:(__unused CFStreamClientContext *)inContext {
    return NO;
}

@end

因此,在子类化NSInputStream时,我正在使用所需的解决方法.

So I'm using workaround needed when subclassing NSInputStream.

现在这应该可行.但是我没有收到任何CppInputStreamWrapper方法的调用(除了我在构造对象时的调用).

Now this should work. But I'm not receiving any call of methods of CppInputStreamWrapper (except for my call when construction object).

没有错误,没有警告,没有!

No errors no warning are reported, nothing!

添加异常断点后,我会捕获

When I've added exception breakpoint I'm catching

thread #8: tid = 0x155cb3, 0x00007fff8b770743 libobjc.A.dylib`objc_exception_throw, name = 'com.apple.NSURLConnectionLoader', stop reason = breakpoint 1.1

这来自我未创建的线程com.apple.NSURLConnectionLoader.

This comes from thread com.apple.NSURLConnectionLoader which I didn't create.

我完全不知所措,不知道还能做什么.

I'm totally puzzled and have no idea what else I can do.

我使用的代码格式为评论链接,它是上的href ="https://github.com/bjhomer/HSCountingInputStream/blob/master/HSCountingInputStream/HSRandomDataInputStream.m" rel ="nofollow">.现在,至少我的课程的某些部分是由框架调用的,但是我看到了奇怪的崩溃.

I've used code form link in comment which is hosted on github.Now at least some parts of my class are invoked by framework, but I see strange crash.

崩溃位于此方法中:

- (BOOL)_setCFClientFlags:(CFOptionFlags)inFlags
                 callback:(CFReadStreamClientCallBack)inCallback
                  context:(CFStreamClientContext *)inContext {

    if (inCallback != NULL) {
        requestedEvents = inFlags;
        copiedCallback = inCallback;
        memcpy(&copiedContext, inContext, sizeof(CFStreamClientContext));

        if (copiedContext.info && copiedContext.retain) {
            copiedContext.retain(copiedContext.info);
        }

        copiedCallback((__bridge CFReadStreamRef)self, kCFStreamEventHasBytesAvailable, &copiedContext); // CRASH HERE
    } else {
        requestedEvents = kCFStreamEventNone;
        copiedCallback = NULL;
        if (copiedContext.info && copiedContext.release) {
            copiedContext.release(copiedContext.info);
        }

        memset(&copiedContext, 0, sizeof(CFStreamClientContext));
    }

    return YES;

}

崩溃为EXC_BAD_ACCESS(在OS X上运行测试时).当我看到这段代码时,一切看起来都很好.它应该工作! self指向保留计数为3的正确对象,所以我不知道为什么它崩溃了.

Crash is EXC_BAD_ACCESS (when running tests on OS X). when I see this code everything looks fine. It should work! self is pointing to proper object with retain count 3 so I have no idea why it is crashing.

推荐答案

未记录的私有桥接API并不是自定义NSInputStream实现中的唯一问题,尤其是在CFNetworking集成的情况下.我建议使用我的 POSInputStreamLibrary 作为基本构建块.而不是实现许多NSInputStream方法并支持异步通知,您应该实现更简单的 POSBlobInputStreamDataSource 接口.至少您可以查看 POSBlobInputStream 来咨询什么样的功能您应该实施以完全支持NSInputStream合同.

Undocumented private bridging API is not the only problem in custom NSInputStream implementation especially in the context of CFNetworking integration. I'd like to recommend to use my POSInputStreamLibrary as basic building block. Instead of implementing a lot of NSInputStream methods and supporting async notifications you should implement much simpler POSBlobInputStreamDataSource interface. At least you can look at POSBlobInputStream to consult what kind of functionality you should implement to support NSInputStream contract completely.

POSInputStreamLibrary 用于最受欢迎的俄罗斯云存储服务 Cloud Mail.Ru 并上传> 1M每天没有任何崩溃的文件.

POSInputStreamLibrary is used in the most popular Russian cloud storage service Cloud Mail.Ru and uploads >1M files per day without any crashes.

祝你好运,随时问任何问题.

Good luck and feel free to ask any questions.

这篇关于带有上传流的NSURLSession-子类化NSInputStream-com.apple.NSURLConnectionLoader异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 23:04