If you are developing a content-based iPhone or iPad app that connects to the internet you have to be prepared for real-world networking. The fast hard-wired connection you have on your development machine and the strong wi-fi signal you get on your device are great for testing things quickly, but they don't prepare your app for what it will face in the hands of iPhone users all over the world. Your app will have to handle network dropouts, packet loss and high ping times without crashing and while maintaining a good user experience.
Airplane mode is not network testing
The first instinct of most mobile developers is to turn airplane-mode on, launch their app, and see if it crashes. This can catch a lot of fundamental coding errors, but if this is the only network testing you do you will miss out on more subtle bugs and user experience problems.
The biggest issue with airplane mode is that it fails fast. As soon as your app enters the foreground the network connection is down and if your App makes a request it will immediately return failure.
In the real world it may take several seconds for your request to return a result or time out. What does your UI look like during this time? You need to show some kind of progress indicator to let the user know their request is processing.
If a network connection is working, but it's slow or spotty, does your app feel sluggish? This can happen if you rely on a fast connection to deliver content.
You'll never see these user experience issues crop up if you only test in airplane mode.
Proxy your development traffic
To test properly you need to be able to run your app with conditions that more closely match the real world conditions it will face. You also want the ability to trigger these conditions yourself for for faster testing. You can achieve this by using an HTTP proxy that supports throttling.
We used this to quickly test the app at speeds comparable to 3G, Edge, and worse. With this it's also easy to simulate connections that begin but eventually drop out after some amount of time.
Running our app under these conditions allowed us to spot trouble areas where the code expected content to be fully loaded but a quickly failing connection would hide the problem.
Charles Proxy also allows you to route traffic from your device through it so you aren't just limited to the simulator.
General strategies for happy network use
The most important thing you can do is also one of the easiest things: load your resources asynchronously. Apple provides plenty of documentation for asynchronous loading of URLs via the NSConnection delegate. Also, a library like ASIHTTPRequest can do a lot of the heavy lifting for you. The latest versions even support using Objective-C blocks instead of delegation.
Doing it this way means that your view can display at anytime before, during, and after a request is made. Your UI should make sense and give the user feedback as to what state their request is in. This also leaves you free to respond instantly to user interaction and it will make your app feel more responsive and fluid.
Cache is king in iOS development
Don't assume that your App will always be able to get fresh data from the network. There are lots of times when the network will be unavailable yet the user will still want to use the App.
If you make a request, store the result somewhere. The next time you need to make that request you can return the cached result right away while the resource is being fetched.
Depending on your needs you may implement this with a simple plist cache or a more fully-featured framework like RestKit.
Images are a whole other issue, but it's been solved for you
A small HTTP request for a bit of JSON or XML can complete relatively quickly. You may not notice any issues even with a slow connection. However, when your App tries to pull down a few megabytes worth of images the problem becomes amplified.
The Apple documentation describes a few ways to load images asynchronously and cache them but I don't think they are ideal. It requires a fair bit of code within your controllers to coordinate which images need to be loaded and when to flush the cache. It can be quite messy and is certainly more complicated than having the images stored locally.
I recommend skipping the whole issue entirely and using SDWebImage. This library provides a category on UIImageView. This category allows you to set a URL for a UIImageView and a placeholder image. The placeholder displays immediately while the URL is loaded in the background. Once the URL is loaded it is swapped in for the placeholder automatically.
SDWebImage also caches all of the images it downloads automatically so you get great performance with slow connections and it will even display when the network is down completely.
You can code as if all of the images in your app are stored locally.
Don't guess, test
It's up to you to make sure your iOS App is the best it can be. Don't send it out in the world hoping that it will work okay. Use the tools you have available to know for sure that it will perform well even when the network doesn't.