Ipphones

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Thursday, 20 March 2008

Network Communications with NSFileHandle

Posted on 07:35 by Unknown
Okay, well, because of the NDA, I can't post code samples about how to do things using the iPhone SDK yet, but I can post regular old Cocoa code without worrying about the Apple lawyers. If that code just happens to be usable on the iPhone also... oh, well.

With the fact that so many people have downloaded the SDK, I have to think at least seven or eight of those people do not have any prior experience using Objective-C or Cocoa. Those people will have a bit of a grokkng curve. I say "grokking" instead of "learning" because the syntax of Objective-C is straightforward and relatively easy to learn. However, the approach it takes is decidedly different from the application frameworks used with Visual Basic, C#, and Java; it takes a little while to really understand the way it all fits together and start working with the frameworks rather than against it.

One of the things that I'm sure many aspiring iPhone developers will want to do in their applications is to communicate with remote servers. Now, any of the old school C programmers who want to do so will have access to BSD sockets and can do network programming just as they have always done. Because Objective-C and Cocoa build on top of C, you always have available to you everything you do when writing procedural C.

But, often, there's a better, or at least, an easier way to do things using existing Cocoa classes. Unfortunately, what that "better way" would be for this isn't quite so straightforward. One option is to use CFNetwork. CF stands for Core Foundation, and when you see something beginning with CF in the world of Apple software development, you are looking at lower level C functions that are used by the higher level libraries like Cocoa and Carbon. CFNetwork underlies many of the higher-level classes capable of communicating with remote servers. When you use NSURLConnection, or instantiate an NSString using stringWithContentsOfURL:encoding:error:, you are using classes that sit on top of CFNetwork.

And CFNetwork is great - it is robust and written to work with an existing run loop mechanism, meaning you don't have to detach threads to keep from blocking. Unfortunately, CFNetwork is conceptually hard and using it in Cocoa creates confusing, hard to maintain classes. Coercing C callbacks into an instance of a Cocoa class works, and it works well, but it just doesn't feel right in the context of Objective-C/Cocoa.

Unfortunately, there is no generic Cocoa class for accessing remote servers. There are lots of special-purpose methods and classes that sit on top of CFNetwork and let you seamlessly get information from over the network using URLs. But what can you do if you want to implement your own protocol, or access a different kind of server?

Well, there are several third party classes that you could use for this, including Dustin Voss' free AsyncSockets and the open source SmallSockets project. These are both good options if you want to use them.

Someone on the Cocoa-Dev mailing list recently pointed out that NSFileHandle is capable of handling socket communications, but you have to actually create the socket the old fashioned way and feed it to NSFileHandle using initWithFileDescriptor: to do so. Thanks to the beauty of Objective-C categories, however, you only have to do it once if you write the code generically and put it in a category.

So, thanks to the help from several people on the Cocoa-Dev list, I present a category on NSFileHandle that lets you get a conection to a remote server. You can download the category right here.

Using this category is very straight forward. You can create a new NSFileHandle that is connected to a remote server like this:
NSFileHandle *fh = [NSFileHandle fileHandleToRemoteHost:@"theremoteserver.com" onPort:80];
To send a command and get the response, you need to create a method (probably on your controller class) that will be called whenever data is available on the read stream. That method might look something like this:
-(void)process:(id)notification
{
NSFileHandle *fh = [notification object];
NSMutableData *data = [fh availableData];
NSString *dataString = [[NSString alloc]
initWithData:data
encoding:NSUTF8StringEncoding];
/* Process the data however you need to here */
[dataString release];
if (booleanVariableThatIndicatesIfWeExpectMoreData)
[fh readInBackgroundAndNotify];
}
Notice the last two lines. If we are expecting more data, we have to call readInBackgroundAndNotify again, or it won't continue to pull more data from the stream and we'll end up with only part of the server's response. If we don't expect more data, we don't have to call readInBackgroundAndNotify any more, and could also close the stream using the closeFile method of NSFileHandle. You could also leave the stream open and send more commands to it. 

If you call readInBackgroundAndNotify and there's nothing to read, your program won't be harmed, but your method won't get called again unless you send another message through to the server. So, if you have processing to do on the retrieved data once you get it all, you need to figure out in your code when you've received everything. Usually the protocol gives you a mechanism for doing that. NNTP, for example, sends a line with just a single period on it to tell you when it's done sending you data, but it leaves the connection open in case you want to send more commands through.

The nice thing here: no threads. Our application goes about its merry way, and calls us back when there's something for us to do. At this point, we've created the file handle, and we've created a method to process the responses from the server, so now we just need to send something to the remote server so that our process: method has something to wait for, which we do like this:
[fh writLine:@"HELO\r\n" withObserver:self andProcessWith:@selector(process:)];
That's all there is to it. 

As I said before, this is Cocoa code, not Cocoa Touch code, but since NSFileHandle is part of the Foundation framework and not the AppKit, it should (in theory) work unchanged in Cocoa Touch. I haven't yet tested it, but I'm going to, and as soon as the NDA lifts in June, I'll tell you if any changes are necessary to get it to work on the iPhone.
Email ThisBlogThis!Share to XShare to Facebook
Posted in CFFoundation, Cocoa, Cocoa Touch, iPhone SDK, NSFileHandle, Sockets | No comments
Newer Post Older Post Home

0 comments:

Post a Comment

Subscribe to: Post Comments (Atom)

Popular Posts

  • Strong Encryption for Cocoa / Cocoa Touch
    Please do not use this code! Instead, check out Jim Dovey's Common Crypto code from AQToolkit . AES is a strong encryption standard tha...
  • Texture Coordinate Arrays or Things Nobody Tells You
    For some reason, a lot of OpenGL stuff just isn't well documented. Yes, I read the Red Book chapter on texturing. It didn't have a s...
  • Dynamically adding class objects
    Okay, folks, the first draft of the book is done, and I have some breathing room until the chapters start coming back from the tech reviewer...
  • Web Services Fun
    Before we work more with libxml, let's talk about web services. Web services are a good practical application of XML and, it would seem ...
  • An OpenGL Project Template for Xcode
    I'm not a fan of the OpenGL ES Application project template that ships with the iPhone SDK. It's a pain in the ass to go in and dele...
  • Handling Double Taps
    Alright, since the NDA is down, let's celebrate by posting some information, shall we? One question that I see posted a lot by new iPhon...
  • Twittering iPhone Developer List
    Tim Haines, the developer of the excellent BurnBall game, has started a list of iPhone developers who use Twitter. The last time I checked,...
  • More on OpenGL and Normals
    In an earlier post I talked about surface normals in OpenGL. In writing the Wavefront OBJ loading class, I've learned far more about no...
  • OpenGL ES From the Ground Up, Part 1 Addendum: Alphabet Soup
    One problem with blog postings is that they are self-edited. For my postings here, I have no external technical review and no copy editing d...
  • Writing
    I'm pretty swamped with writing work at the moment. The book project is going pretty well, and I'm fortunate to have a very experien...

Categories

  • 3D Models
  • Ad Hoc Distribution
  • ADC
  • Address Book
  • Amazon
  • Anaglyphs
  • App Store
  • Apple
  • Apple DTS
  • Apple Store
  • Application Store
  • articles
  • Award
  • Background Processing
  • Barcodes
  • Beta
  • Blog
  • Blogger
  • Blogging
  • Blogs
  • Blogspot
  • Book project
  • Bug Reporting
  • Captain Obvious
  • Categories
  • Censorship
  • CFFoundation
  • CGAffineTransform
  • Clang Static Analyzer
  • Cocoa
  • Cocoa Touch
  • Code Reuse
  • Code Signing
  • Computer
  • conferences
  • Controller Classes
  • Core Animation
  • Daring Fireball
  • Database
  • Debugging
  • Defect
  • Delegates
  • Design Awards
  • Developer Certifications
  • Discussion Forums
  • Edit Mode
  • employment opportunities
  • Encryption
  • Enterprise
  • Errata
  • free code
  • Free software
  • Full Screen
  • Game Programming
  • Gestures
  • Getting Started
  • goof
  • Google Code
  • Google Maps
  • Gotcha
  • Help
  • HIG
  • HTTP PUT
  • Idiots
  • Idle Timer
  • Images
  • Instruments
  • Interface Builder
  • iPHone
  • iPhone Applications
  • iPhone Dev Center
  • iPhone Developers
  • iPhone OS 3.0
  • iPhone SDK
  • iPhone SDK PNG
  • iPhone Simulator
  • iPhoneSDK
  • iPod
  • Job Opportunities.
  • k
  • Key Value Observing
  • Keynote
  • KVO
  • Landscape Mode
  • Learn Cocoa
  • Learn Cocoa on the Mac
  • libxml
  • Licensing
  • Mac Developers
  • Mac OS X
  • Macworld Expo
  • Microsoft
  • NDA
  • NeHe
  • New Category
  • New Release
  • NSFileHandle
  • NSMutableArray
  • NSMutableURLRequest
  • NSXML
  • Object-Oriented Design
  • Objective-C
  • Open Source
  • OpenGL ES
  • Optimizations
  • Other blogs
  • Paired Arrays
  • Parsing
  • Particle Engine
  • Party
  • PeopleSoft
  • Performance
  • Persistence
  • Pink Screen of Death
  • Piracy
  • Pixar
  • Podcasts
  • Press Release WTF
  • Press Releases WTF
  • private APIs Google
  • Project Template
  • Properties
  • Random Numbers
  • Rant
  • Rejected
  • Resources
  • Responder Chain
  • REST
  • Reverse Engineering
  • Rumors
  • Runtime
  • Sample Code
  • Screencast
  • screenshot
  • Scroll Views
  • snippet
  • Snow Leopard.
  • SOAP
  • Sockets
  • Source
  • Splash Screen
  • SQLite
  • SQLitePersistentObjects
  • Steve Jobs
  • Steve-Note
  • Strings
  • Stupidity
  • Subversion
  • Table Views
  • Taps
  • Template
  • Tip
  • Tips
  • Tririga
  • tutorials
  • Twitter
  • UIAlertView
  • UIColor
  • UIImage
  • UIPickerView
  • UIScrollView
  • UITextField
  • UIView
  • UIWebView
  • Update
  • Utilities
  • UUID
  • Vacation
  • Version Control
  • Web Services
  • Writing
  • WTF
  • WWDC
  • Xcode
  • XML

Blog Archive

  • ►  2009 (141)
    • ►  May (14)
    • ►  April (30)
    • ►  March (48)
    • ►  February (26)
    • ►  January (23)
  • ▼  2008 (163)
    • ►  December (46)
    • ►  November (25)
    • ►  October (44)
    • ►  September (2)
    • ►  August (5)
    • ►  July (2)
    • ►  June (9)
    • ►  May (2)
    • ►  April (11)
    • ▼  March (17)
      • On Managing iPhone & Mac Developers in the Enterprise
      • Beta 2 is out!
      • Getting Started on the iPhone: A Primer for Non-Ma...
      • Network Communications with NSFileHandle
      • Problems Reading and Writing Files on the iPhone?
      • Brain Surgery?
      • The iPhone and the Enterprise
      • Still Playing
      • A Splash of Cold Water
      • Daring Fireball on "One App at a Time"
      • An iPhone App
      • Developer Certs and iPhone OS 2.0
      • Good Googly Moogly! 100,000 downloads
      • On Censorship and the iPhone Application Store
      • I Love Mac Developers
      • Rogue Amoeba
      • And We're Off...
Powered by Blogger.

About Me

Unknown
View my complete profile