{"id":449,"date":"2011-09-08T23:20:31","date_gmt":"2011-09-09T05:20:31","guid":{"rendered":"http:\/\/benincosa.com\/blog\/?p=449"},"modified":"2014-11-19T11:24:53","modified_gmt":"2014-11-19T17:24:53","slug":"ios-nsstreamdelegates-grand-central-dispatch-nsnotificationcenter","status":"publish","type":"post","link":"https:\/\/benincosa.com\/?p=449","title":{"rendered":"iOS NSStreamDelegates, Grand Central Dispatch, &#038; NSNotificationCenter"},"content":{"rendered":"<p>One of the more difficult design patterns I&#8217;ve managed to get working in Objective-C while developing an iOS app is one that requires NSStreamDelegates, Grand Central Dispatch (GCD) and NSNotificationCenter. \u00a0This design pattern comes into play in the following situation:<\/p>\n<ul>\n<li>Application launches<\/li>\n<li>Application does some communication with a server in the background<\/li>\n<li>When the server communication in the background is complete, the View Controller is updated to display information from the server.<\/li>\n<\/ul>\n<p>Its a pretty common scenario and I&#8217;m sure one that has many answers. \u00a0In my case, I needed to use CFReadStreams and CFWriteStreams due to the way the client server communication works. \u00a0So if there was a simpler way to do it, I&#8217;d love to know.<\/p>\n<p>The design pattern that I used at a high level to accomplish this is as follows:<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>Application launches, \u00a0displays its first View Controller<\/li>\n<li>This first View Controller in viewDidLoad registers an observer with NSNotificationCenter and then kicks off a background request via GCD to do all the client\/server communication<\/li>\n<li>The background request that launches is an NSStreamDelegate object. \u00a0It sends info to the server.<\/li>\n<li>Once the background request receives information from the server, it sends a notification to NSNotificationCenter that the client\/server communication is complete<\/li>\n<li>Finally, the first View Controller gets this notification, and then updates its View with that info.<\/li>\n<\/ul>\n<p>That&#8217;s the high level. \u00a0So now lets go through and flesh out the details.<\/p>\n<h2>Application Launch and First View Controller<\/h2>\n<p>This is a simple example, but its just to get you the basic idea. \u00a0This part is standard in most iOS apps. \u00a0The thing to note about this is that my FirstViewController is not an NSStreamDelegate. \u00a0It does however contain an object that is an NSStreamDelegate. \u00a0This is called my Communicator class.<\/p>\n<pre>...\r\n#import \"Communicator.h\"\r\n@interface FirstViewController : UIViewController  {\r\n    UILabel *info\r\n    Communicator *myComm;\r\n    UIActivityIndicatorView *spinner;\r\n}\r\n...\r\n\/\/ @property stuff here...<\/pre>\n<h2>First View Controller viewDidLoad<\/h2>\n<p>Here&#8217;s where we start to get cool. \u00a0viewDidLoad looks something like this:<\/p>\n<pre>- (void)viewDidLoad\r\n{\r\n    \/\/ Let user know that something is happening.. spin the spinner..\r\n    [spinner startAnimating];\r\n    \/\/ register for notification of updates.\r\n    [[NSNotificationCenter  defaultCenter] addObserver:self selector:@selector(updateView) name:@\"updateView\" object:nil];\r\n    \/\/ create a thread and get the server updates.\r\n    dispatch_async(dispatch_get_global_queue(0, 0), ^{\r\n        myConnectionInfo = [[Connection alloc] initWithStuff:@\"Stuff\"\r\n        myComm = [[Communicator alloc] initWithConnection:myConnection];\r\n        [myComm communicate:@\"Send this message\"]\r\n    });\r\n    [super viewDidLoad];\r\n}<\/pre>\n<p>A few things to note here:<\/p>\n<p>1. \u00a0We add an observerer to NSNotificationCenter. \u00a0This basically says: \u00a0If someone sends the updateView message, then I&#8217;ll respond to it with my updateView method. \u00a0(We&#8217;ll show this later)<\/p>\n<p>2. \u00a0We dispatch an\u00a0asynchronous\u00a0task to GCD. \u00a0That&#8217;s what this whole dispatch_async business is all about. \u00a0This way, the view controller will just display while this task runs in the background.<\/p>\n<p>3. \u00a0We instantiate myComm and initiate it with some connection info. \u00a0This info might be something you got from the app delegate, some other view controller, or a plist. \u00a0That part is left to you to decide.<\/p>\n<h2>NSStreamDelegate actions<\/h2>\n<p>Our class Communicator is a NSStreamDelegate. \u00a0Here&#8217;s some of the relevant header info:<\/p>\n<pre>...\r\n@interface Communicator : NSObject &lt;NSStreamDelegate&gt; {\r\n    NSInputStream *inputStream;\r\n    NSOutputStream *outputStream;\r\n    NSString *theResult;\r\n    NSString *cmd;\r\n    Connection *myConn;\r\n}\r\n\/\/... @property stuff here... and functions<\/pre>\n<p>Nothing big here, just the NSInputStream (the stream we get info from the server) and the NSOutputStream (The stream we write to the server)<\/p>\n<p>As part of the initialization of the Communicator, we have a function called startConnection.  This can be called in the init methods.  (provided you have all the server communication info: (e.g: user, password, server, port, etc).<\/p>\n<p>Our&#8217;s has this:<\/p>\n<pre>    self.inputStream = (NSInputStream *)readStream;\r\n    self.outputStream = (NSOutputStream *)writeStream;\r\n    [inputStream setDelegate:self];\r\n    [outputStream setDelegate:self];\r\n\r\n    \/\/ schedule on the main run loop\r\n    dispatch_async(dispatch_get_main_queue(), ^ {\r\n\r\n        [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];\r\n        [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];\r\n\r\n        [inputStream open];\r\n        [outputStream open];<\/pre>\n<pre>     });<\/pre>\n<p>The important part here is what you do before you schedule your input and output streams on the RunLoop. \u00a0<a href=\"http:\/\/developer.apple.com\/library\/mac\/#documentation\/Cocoa\/Conceptual\/Streams\/Articles\/PollingVersusRunloop.html#\/\/apple_ref\/doc\/uid\/20002275-CJBEDDBG\">The RunLoop is the preferred way to work with NSStreamDelegates<\/a>. \u00a0You have to make sure that you put it running back on the main thread&#8217;s runloop. \u00a0That&#8217;s what this whole dispatch_async(dispatch_get_main_queue() bit is about. \u00a0If you leave this out, then you&#8217;ll never get any connections going on.<\/p>\n<p>Once you open the connections and you do your reading and writing in the handleEvent function:<\/p>\n<pre>-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {<\/pre>\n<pre>\/\/ clever code here.<\/pre>\n<pre>}<\/pre>\n<p>Then once you finally get the data from the input stream you send a notification. \u00a0This is done for us in the<\/p>\n<pre>case NSStreamEventEndEncountered:<\/pre>\n<p>we run:<\/p>\n<pre>[[NSNotificationCenter defaultCenter] postNotificationName:@\"updateView\" object:nil];<\/pre>\n<p>Before we do that, however, we set our theResult NSString to the value we received.<\/p>\n<h2>Updating View in First View Controller<\/h2>\n<p>Back in the FirstViewController, we have a function updateView:<\/p>\n<pre>- (void)updateView {\r\n    \/\/NSLog(@\"Got the update\");\r\n    dispatch_async(dispatch_get_main_queue(), ^{\r\n        info.text = myComm.theResult;\r\n        [spinner stopAnimating];\r\n        spinner.hidden = TRUE;\r\n    });\r\n}<\/pre>\n<p>Notice here that once again we need to make sure it goes back on the main thread before we update the view.  Then, since our Communicator belongs to our ViewController, we can get the result of the client\/server communication through the getter and set the UILabel to that result.<\/p>\n<h2>Summary<\/h2>\n<p>As mentioned before, there are probably lots of ways to do this and some are probably better than what I&#8217;ve mentioned here. \u00a0However, this was pretty tricky to me to figure out and once I did, I thought it was worth sharing as I couldn&#8217;t find any holistic info on it via any search engines.<\/p>\n<p>I&#8217;d be curious to know if this helps anybody. \u00a0Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the more difficult design patterns I&#8217;ve managed to get working in Objective-C while developing an iOS app is one that requires NSStreamDelegates, Grand Central Dispatch (GCD) and NSNotificationCenter. \u00a0This design pattern comes into play in the following situation: Application launches Application does some communication with a server in the background When the server&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[27,995,28,127,36],"tags":[129,130,131,128],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/449"}],"collection":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=449"}],"version-history":[{"count":4,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/449\/revisions"}],"predecessor-version":[{"id":2782,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/449\/revisions\/2782"}],"wp:attachment":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=449"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=449"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=449"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}