1 Reply
      Latest reply on Feb 15, 2019 1:53 AM by eskimo
      iOSerKi Level 1 Level 1 (0 points)

        I want to use the CFReadStream to implement downloading in background, via setting the kCFStreamNetworkServiceTypeBackground.

        CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeBackground);
        NSDictionary *settings = @{CFBridgingRelease(kCFStreamSSLPeerName) : _request.host};
        CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, (__bridge CFDictionaryRef)settings);
        CFReadStreamSetClient(readStream, kStreamEvents, requestCallback, &context);
        
        static void requestCallback(CFReadStreamRef _Null_unspecified stream, CFStreamEventType type, void * _Null_unspecified clientCallBackInfo) {
            CFReadStreamViewController *controller = (__bridge CFReadStreamViewController *)clientCallBackInfo;
            switch (type) {
                // ....
                case kCFStreamEventHasBytesAvailable: {
                    NSUInteger bytesRead = 0;
                    uint8_t buffer[1024];
                    bytesRead = [controller.inputStream  read:buffer maxLength:sizeof(buffer)];
                    if (bytesRead > 0) {
                        NSData *data = [[NSData alloc] initWithBytes:buffer length:bytesRead];
                        NSLog(@"%ld bytes read------", data.length);
                    }
                }
                    break;
                // .....
            }
        }
        

        But when I press the home button of iPhone, the app enter the background, then no any logs in Xcode debug console. That means the download was suspended?

         

        By the way, in order to support SNI, I use the CFReadStream instead of the NSURLSession.

         

        Thanks for answering!

        • Re: The kCFStreamNetworkServiceTypeBackground for CFReadStream doesn't work.
          eskimo Apple Staff Apple Staff (10,585 points)

          You have misunderstood what this stream type does.  It does not enable your app to run a TCP connection for an arbitrarily long amount of time in the background.  Rather, it’s all about quality of service (QoS), both within the kernel and on the ‘wire’.

          Looking at the documentation for this API, it’s easy to see how you were lead astray.  I’ve filed a bug (r. 48105066) about that.

          In the meantime, the absolute best place to find information about these QoS values is the comments for the various SO_NET_SERVICE_TYPE values in <sys/socket.h>.  And if you’re interested in more background info, watch WWDC 2016 Session 714 Networking for the Modern Internet.


          Coming back to your actual goal, if you want to download a large resource while your app is in the background then NSURLSession is your only good choice.  You wrote:

          By the way, in order to support SNI, I use the CFReadStream instead of the NSURLSession.

          What do you mean by this?  I assume you’re referring to Server Name Indication, and that’s definitely supported by NSURLSession.  Is that support insufficient?  If so, please elaborate.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"