创建博客 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

lionYue

毋意,毋必,毋固,毋我

 
 
 

日志

 
 

UITables with Downloaded Images - Easy Asynchronous Code  

2009-07-08 09:54:33|  分类: 默认分类 |  标签: |举报 |字号 订阅


Posted by markj on February 21, 2009 · 38 Comments 

postcards-screen1The app ‘Postcards’ from my iPhone developer training class is a utility app for quickly sending a customized postcard, and one thing that makes it super easy is that you can grab pictures from Flickr to include in the postcard design. Postcards makes simple HTTP calls Flickr’s REST API to download public domain images and displays them in a UITableView for the user to pick from. Cocoa Touch makes this all simple and easy to code, and my first development version used synchronous calls to get the images by using NSData dataWithContentsOfURL:

.

.

NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urls]];

Making synchronous calls to remote web servers from the thread that’s running the apps GUI is of course a bad idea that results in a laggy UI and unsatisfied users. Using synchronous calls in UITableView cellForRowAtIndexPath to load all the images results in a problem six times worse (for 6 rows on the screen) and makes scrolling basically broken as the table won’t scroll until it has the next cell, which it can’t get while the app is waiting for an image to download. Then imagine that on the Edge network! Obviously we need something multi-threaded that can load the images in parallel in the background and update the UI as they finish downloading.

Multi-threaded programming is hard and should be avoided whenever possible, and in this case Cocoa’s beautiful design came to my rescue:

UIView heirachy + URL loading system + delegate design = multi-threaded image loading with no multi-threaded coding!

How can you have your cake and eat it too? Every iPhone app is a multi-threaded program, or at least its running in conjuction with the multi-threaded iPhone operating system. Use the right delegate methods in the right ways, and you can take advantage of extra threads of execution that the iPhone gives you for free without writting any multi-threaded code of your own, hence sidesteping the problem of threading bugs in your code. An iPhone app is one big event loop - your classes have methods that the event loop calls in response to stuff happening on the device and in your app. When you use the URL loading system’s asynchronous APIs, the iPhone uses a different thread than the one running your app’s event loop to load the contents of the URL, and it makes callbacks via your apps event loop when data has been downloaded.

connection = [[NSURLConnection alloc]
initWithRequest:request delegate:self];
 
- (void)connection:(NSURLConnection *)theConnection
didReceiveData:(NSData *)incrementalData

Note carefully, when data has arrived from the remote webserver, that other iPhone thread doing the downloading doesn’t make calls into your objects at the same time as your methods are running, it puts messages into your apps event loop. If it called your app directly then chances are your app would be running some UI code or something and you’d have to write thread safe code. Instead, the call that data is ready arrives as an event on the event loop. Events on the event loop run single threaded, one at a time. Using this we can get asynchrous image download from Flickr without writting thread safe code ourselves. Even better, Cocoa’s URL loading system will download those URLs in parallel! For free!

That’s all well and good, but how do you get a table view to update the UITableViewCell with the image after its already been returned? A UIImage is imutable (right?) so you can’t change its image later when the image data has downloaded. Turns out Apple made this super easy too. Instead of putting a UIImage in the UITableViewCell, you put your own UIView object, that is sized correctly for the image you want to display, into the content view of the UITableCell (as a subview). At first your view object it can be empty, or it can have a dummy image in it, or you can pop in one of those spinny ’something is happening’ views. Then when the image data is downloaded, create a UIImageView with the image and pop it in your view in the cell. Hey presto… it appears. While all this is happening the user can be scrolling and going back and forth with a fully functioning UI.

I put this all together in a class AsyncImageView, listed below. It’s use is simple

  1. alloc and initWithRect:
  2. add it to a view, eg in a table cell’s content view;
  3. send it the loadImageFromURL: message.

LoadImageFromURL will return right away, the image will load in the background, and will automatically appear in the view when its finished downloading. The code posted below is something I whipped up pretty quickly (and I didn’t leak check yet!), but hey - parallel, asynchronous image download and display in about 40 lines of code with no thread-safe worries? Works in smooth scrolling tables, even on the Edge network? I rate it a big win, and wanted to share the technique.

I’ve developed an iPhone programming training class that I will be teaching soon in the SFBay Area (though my partners and I could probably bring it to you). It’s very hands on, and specially designed to help professional programmers new to Cocoa and Objective-C over the difficult initial learning curve. In the class we build the Postcards app from start to finish, including AsyncImageView. Email me for more info: markj at markj.net

AsyncImageView.h

AsyncImageView.m

@interface AsyncImageView : UIView {
NSURLConnection* connection;
NSMutableData* data;
}
@end
 
@implementation AsyncImageView
 
- (void)loadImageFromURL:(NSURL*)url {
if (connection!=nil) { [connection release]; }
if (data!=nil) { [data release]; }
NSURLRequest* request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
connection = [[NSURLConnection alloc]
initWithRequest:request delegate:self];
//TODO error handling, what if connection is nil?
}
 
- (void)connection:(NSURLConnection *)theConnection
didReceiveData:(NSData *)incrementalData {
if (data==nil) {
data =
[[NSMutableData alloc] initWithCapacity:2048];
}
[data appendData:incrementalData];
}
 
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
 
[connection release];
connection=nil;
 
if ([[self subviews] count]>0) {
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
 
UIImageView* imageView = [[[UIImageView alloc] initWithImage:[UIImage imageWithData:data]] autorelease];
 
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth || UIViewAutoresizingFlexibleHeight );
 
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout];
[self setNeedsLayout];
[data release];
data=nil;
}
 
- (UIImage*) image {
UIImageView* iv = [[self subviews] objectAtIndex:0];
return [iv image];
}
 
- (void)dealloc {
[connection cancel];
[connection release];
[data release];
[super dealloc];
}
 
@end

And here is the usage in UITableViewCell. The AsyncImageView gets tagged with 999, and when it gets recycled, that 999 tagged view gets fished out and removed. So only the cell is being recycled, not the AsyncImageView object. When its removed from the cells content view it also gets released, causing dealloc, which in turn cancels the url download (if its outstanding).

- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 
static NSString *CellIdentifier = @"ImageCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithFrame:CGRectZero reuseIdentifier:CellIdentifier]
autorelease];
} else {
AsyncImageView* oldImage = (AsyncImageView*)
[cell.contentView viewWithTag:999];
[oldImage removeFromSuperview];
}
 
CGRect frame;
frame.size.width=75; frame.size.height=75;
frame.origin.x=0; frame.origin.y=0;
AsyncImageView* asyncImage = [[[AsyncImageView alloc]
initWithFrame:frame] autorelease];
asyncImage.tag = 999;
NSURL* url = [imageDownload
thumbnailURLAtIndex:indexPath.row];
[asyncImage loadImageFromURL:url];
 
[cell.contentView addSubview:asyncImage];
 
return cell;
}

[Slashdot] [Digg] [del.icio.us] [StumbleUpon]

Filed under App Development · Tagged with Add, new, tag

Best Books for iPhone Development

Posted by markj on January 15, 2009 · 9 Comments 

Some brilliant iPhone developer books are out now which are great for learning iPhone native app and web development, and handy references for existing Cocoa Touch experts. In this article I review several titles and give you my pick of the best for learning the native SDK and Objective-C programming:

iPhone in Action

iPhone in Action has very broad coverage of developing for the iPhone, and it introduces everything you need to know. The first third of the book covers web stuff - both how to revamp your existing website so it works great on both the desktop and iPhone, and also how to create iPhone specific web apps. Topics include design, CSS, iUI (the awesome library to make native looking web apps), graphics with webkit canvas, Dashcode, and debugging tips. The middle third of the book gets you started with native SDK development, starting with an overview of Objective-C and XCode, and then on to lots of good step by step tutorials for learning how to use Interface Builder and the different kinds of view controllers to create your GUI. The final third is an intro to important SDK programming topics including graphics, web interaction, SQLite databases, using the address book, etc. The book is invaluable for beginners because it shows you all the possibilities of both web and SDK and it introduces all the key topics - something no other single title does. Experts will want this title too for the detailed web development topics.

Beginning iPhone Development - Exploring the iPhone SDK

This fantastic book is an APress title, I don’t know how they do it but APress has great authors and every APress book I get is a home run. The book explains how to use the Cocoa SDK to write iPhone apps in very clear easy to digest steps. It has a lot more detail and an easier pace than ‘iPhone in Action’. View controllers are the most important part of the SDK to get to grips with, and they are the hardest to figure out. In this title we get 200 delicious pages devoted to them, compared to just 60 in ‘iPhone in Action’. ‘Beginning iPhone Development’ only covers the SDK and Interface Builder, so it has room for some useful SDK topics you won’t find written about elsewhere like UI’s that rotate to landscape mode and localization for different countries. This is the best book for learning native iPhone development.

Learn Objective-C on the Mac

Also on APress, this is _the_ book for learning and mastering Objective-C. Great writing, very easy to understand, and excellent as both a tutorial and reference. The authors assume you already know a little C syntax (from C, C++, Java, etc), so this is the key text for switchers. Still not figured out memory management retain counts and auto-release pools? Protocols, categories and inheritance a mystery? It’s all in this book. Recommended for all iPhone developers.

The iPhone Developer’s Cookbook

A great collection of recipes for using the SDK in the form ‘how to make my iPhone app do X’ format. These programming nuggets are lying on the page waiting for you to pinch ‘em and drop right into your own apps saving lots of time and giving you some great new ideas. Beginners and experts alike will learn many new tricks, everything is explained with clarity and brevity. For example after just 1 hour with this book I realized that my own app had buggy table views that I was able to easily fix using recipes from the book. Some of the recipes even mention undocumented APIs that allow neat UI details you’ve seen in Apple’s apps but otherwise couldn’t figure out how to do. This book should stay by any iPhone developers side.

…and a few more

Here are some additional books you might find helpful

‘Learn C on the Mac’. If you’ve never programmed any C or C++ you might also want to check out this book, also on Apress. Some iPhone programming is done with are pure C APIs, eg SQLite, Quartz 2D Graphics, OpenGL, and there’s also a lot of use of C structs throughout Cocoa. To use these you’ll have to get your C pointers syntax right, and of course Objective-C is a super set of C anyway, so brush up your C.

Programming in Objective-C. This comprehensive reference covers  everything about the language, both the C and Objective-C parts.

Cocoa Programming for Mac OS X (third edition), Aaron Hillegass. OK, this isn’t an iPhone book, its a Mac programming book, and this is the book I learned Cocoa and Objective-C from before all the iPhone books came out! There’s a lot in common between iPhone development and Mac development, so if you are confused and want to read the basics explained with a different voice, this is somewhere you can turn. Let’s hope the author comes out with an iPhone version.

XCode Unleashed Fritz Anderson. New to Apple development means new to XCode, so if you want a book to help you make XCode bend to your will, this is where to turn. While you might not want to read 500 pages about an IDE, its good to have as a  reference, for learning a few productivity tricks, and it includes lots of information on debugging, Shark and Instruments, source code control, unit testing, documenting your code, etc.

Apple’s Documentation. Of course you don’t need a review of Apple’s extensive and free documentation because you already read it all right? No? You got lost and gave up once you started trying to write your app? (I did at first.) With one or all of the books above to get you going, dip back into Apple’s excellent documentation for lots more gory detail. Once you’ve got the hang of  Cocoa and Objective-C you’ll see that Apples documentation is excellent, and you’ll be hitting command-option-shift-/ all the time in XCode. As well as all the API documentation, pay special attention to the Human Interface Guidelines, breaking these guidelines can get your app rejected.

[Slashdot] [Digg] [del.icio.us] [StumbleUpon]

Filed under App Development, Books · Tagged with book, Cocoa, Objective-C

  • Categories

  • Recent Posts

  • Meta

  •   评论这张
     
    阅读(3672)| 评论(1)
    推荐 转载

    历史上的今天

    最近读者

    热度

    在LOFTER的更多文章

    评论

    <#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
     
     
     
     
     
     
     
     
     
     
     
     
     
     

    页脚

    网易公司版权所有 ©1997-2014