Michael Yue Michael Yue - 12 days ago 8
Swift Question

Scheduling socket communication for Swift

I am fairly new to Swift programming, please forgive the dummy questions I have got to ask below.

In my app, I am trying to schedule to call a function, which will receive some data from my server and will be called every second. The communication needs to be achieved via a TCP socket. After doing some research, it seems to me that I need to have a way to properly use threads to call that function. So here comes my questions:


  1. Where should I make the connection to the server? (Should I make the connection in the viewDidLoad() function of my first view controller?)

  2. Where should I create a thread to schedule the function call? If I create the thread inside my first view controller, would the thread die after I switching to another view controller?

  3. What QoS level I should use for that thread? The app is rendering the data received from the server every second, so I assume this task would have a very high priority.



I tried looking for tutorials and examples about threads and socket communications, but I could not find information that is applicable to my app. So any help or insight regarding the design would be greatly appreciated!

Thanks in advance!

Answer

According to me, the following can be done for the scenarios presented in the question

  1. If you are going to make connection to your server as soon as you launch the app. I believe it's better to do that in AppDelegate in didFinishLaunchingWithOptions given below

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    
    }
    
  2. It depends on how you are going to switch to other ViewController. In the process of switching if you are going to deallocate your current ViewController, then your thread will die.

  3. Considering that you're making a socket based app and you will be receiving data from server every second. Then, NSURLSession might not be of much help to you. For socket communication, normally NSInputStream and NSOutputStream will be used. The following example from objective-C may help you to get started:

     - (void)connectWithHostFromUrl: (NSURL *)hostUrl {
    
            CFReadStreamRef readStream;
            CFWriteStreamRef writeStream;
            CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)[hostUrl host], 80, &readStream, &writeStream);
    
           _inputStream = (__bridge_transfer NSInputStream *)readStream;
           [_inputStream setDelegate:self];
           [_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
           [_inputStream open];
    
           _outputStream = (__bridge_transfer NSOutputStream *)writeStream;
           [_outputStream setDelegate:self];
           [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
           [_outputStream open];
      }
    
     // Delegate methods
    
    - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
    
            switch (eventCode) {
                 case NSStreamEventNone:
                 {
                  // handle it according to your need
                 }
                      break;
                 case NSStreamEventOpenCompleted:
                 {
                  // handle it according to your need
                 }
                      break;
                 case NSStreamEventHasBytesAvailable:
                 {
                     if (_receivedData == nil) {
                          _receivedData = [NSMutableData new];
                     }
                     uint8_t buffer[1024];
                     NSInputStream *inputStream = (NSInputStream *)aStream;
                     NSInteger bytesReceived = [inputStream read:buffer maxLength:1024];
                    if (bytesReceived > 0) {
                        [_receivedData appendBytes:(const void *)buffer length:bytesReceived];
                    }
                 }
                      break;
                 case NSStreamEventHasSpaceAvailable:
                 {
                      if (_dataToSend != nil) {
                        // _dataToSend is NSMutableData/NSData object
                          NSOutputStream *outputStream = (NSOutputStream *)aStream;
                          const uint8_t *mutableBytes = (const uint8_t *)[_dataToSend mutableBytes];
                          NSInteger length = [_dataToSend length]/sizeof(uint8_t);
                          [outputStream write:(const uint8_t *)mutableBytes maxLength:length];
                      }
                  }
                      break;
                  case NSStreamEventErrorOccurred:
                  {
                    // handle it according to your need
                  }
                      break;
                  case NSStreamEventEndEncountered:
                  {
                    // handle it according to your need
                  }
                      break;
                  default:
                      break;
           }
    }
    

Since there are a lot of cases to handle here. Most of the time, I suggest using a tested third party library like SocketRocket.

Please suggest edits to make this answer better :)

Comments