Using the netinet functions on iPhone causes the UI to not refresh
I'm including开发者_如何学JAVA the netinet headers and doing some raw socket programming on the iPhone, and have found when making these calls, the UI won't refresh until I'm finished- any response I get and write to the UI, isn't written until the IBAction that made the call is complete. Using performSelector with a delay, I've been able to work around this, but I was wondering if there is a better way of handling this?
In keeping with the general philosophy that it's best to pick the highest level abstraction that is usable for you, I'll suggest that perhaps CFSockets might also be a possibility.
CFSocket is sufficiently low-level that you can likely do whatever form of network communications you're attempting, but it will help you by adding Run Loop integration. By using the run loop, you can avoid having to multi-thread your code. Using the run loop treats network events like any other source of events for your application.
See the CFNetwork Programming Guide for more information.
You can detach a new thread and run your network code in that method:
[NSThread detachNewThreadSelector:@selector(doNetworkStuff:) toTarget:self withObject:nil];
// ...
- (void) doNetworkStuff:(id)_param {
NSAutoreleasePool *_pool = [[NSAutoreleasePool alloc] init];
// ... do netinet stuff here
[_pool release];
}
By doing network stuff in its own thread, you leave the UI free to perform updates.
The easiest way I have found is to spin up a second thread. Read the Threading Programming Guide.
I then communicate back to the UI via performSelectorOnMainThread:withObject:waitUntilDone:. It's easy to send and NSObject that encapsulates the data received from the network.
For example, if my networking code could query Stack Overflow for a bunch of questions, then I might have:
@interface Question {
NSString *question;
NSString *answer;
}
@end
@interface QuestionQueryResults {
NSMutableArray *questions;
}
@end
and I have a view controller with the following public method:
@interface QuestionsController : UIViewController {
}
- (void)setQuestions:(QuestionQueryResults*)questions;
@end
The setQuestions
method will then populate all your textboxes, reload the table view, and whatever needs to be done.
The threading code would go something like:
void performQuery(QuestionsController *delegate) {
QuestionQueryResults *results = [[QuestionQueryResults alloc] init];
// Process the network data to fill in results
[delegate performSelectorOnMainThread:@selector(setQuestions:)
withObject:results
waitUntilDone:YES]; // Wait so we can `release` the results
[results release];
}
You could consider QuestionQueryResults
as the "ViewModel" in an MVC architecture. Works great and produces minimal UI glitches.
精彩评论