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

  • Making OpenGL ES Screenshot
    The Bit-101 Blog has an entry that shows how to take a screenshot when using OpenGL ES . I tested this in my much-delayed particle-generato...
  • Adding CLANG to Your Build Process
    Frasier Spiers has a nifty piece this morning on using Git pre-commit hooks to automatically run the CLANG Static Analyzer. I'm not a G...
  • CLANG Static Analyzer
    If you aren't using the LLVM/Clang Static Analyzer , you really should be. The Clang Project is an attempt to write a front end for the...
  • A Little Help
    I'm having a problem with OpenGL ES, and it's keeping me from finishing my particle engine post. I was hoping someone here could see...
  • WWDC Accommodations
    Staying downtown in San Francisco is very expensive in the summertime. Bu, if you're going to WWDC, you really want to stay downtown. Yo...
  • Xcode File Templates and a Mystery
    One of the things that confuses many newcomers to Xcode is how to set it up so that your company name gets automatically filled in when you ...
  • Brain Surgery?
    Craig Hockenberry has an interesting post on his blog today about the iPhone background processing issue. Craig speaks from personal experi...
  • Book's Almost Done
    I just finished Chapter 16. I'll give it another read-over in the morning then it will go off to my writing partner for his review, then...
  • iPhone Alley
    Looks like Dave and I are going to make an appearance on the iPhone Alley Podcast next week. We're recording on Sunday night, so I woul...
  • Shuffling Arrays
    Ever want to randomize an array of items? It's a task that, for some reason, I've had to do a lot in recent programs. So, I wrote a ...

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