This is part of an ELC Tech Network

Using NSXMLParser to Pull UIImages From the Web

Introduction

Hello everyone, welcome to my third screeencast. This screencast is the result of a request made in the comments of my first post. I am going to be covering many topics in this post. But the general idea of the app we will build is that it will use an XML file online to get the URL and title of a given picture. For each URL and Title pair a view will be created with a UIImageView showing the image and a UILabel showing the title. Each of these views will be placed in a UIScrollView to flip through, like th functinoality of the Photos app.

Skill Level Medium

This app is going to require a decent amount of experience with Objective C and xCode. Also some minimal understanding of XML and XML schema/structure would be valuable.

Source Code

Available Here

Screencast

I film myself coding out the entire sample project for each post. I personally think going through the Screencast is the best way to learn. But feel free to look through the slides and text if that suites you better.

iCodeBlog: Using NSXMLParser to pull UIImages off the Web from Collin Ruffenach on Vimeo.

SCREENCAST ADDITION

Adding a final line to layoutSubviews should be:
     [scrollview setFrame:workingFrame];

this will stop the scroll view from bouncing up and down.

Tutorial

picture-32

picture-41

picture-5

picture-61

picture-71

picture-81

picture-91

picture-101

picture-111

picture-121

picture-131

picture-141

picture-151

iCodeBlogXMLImagesViewController.h:

@interface iCodeBlogXMLImagesViewController : UIViewController
{
	IBOutlet UIScrollView *scrollview;
}

@property (nonatomic, retain) IBOutlet UIScrollView *scrollview;

iCodeBlogXMLImagesViewController.m

@synthesize scrollview;

picture-161

Advertisement

picture-171

picture-181

picture-191

iCodeBlogXMLView.h:

@interface iCodeBlogXMLView : UIView
{
	IBOutlet UIImageView *imageView;
	IBOutlet UILabel *title;
}

@property (nonatomic, retain) IBOutlet UIImageView *imageView;
@property (nonatomic, retain) IBOutlet UILabel *title;

@end

iCodeBlogXMLView.m

@synthesize imageView;
@synthesize title;

picture-201

picture-211

picture-221

picture-23

iCodeBlogXMLElement.h:

@interface iCodeBlogXMLElement : NSObject
{
	UIImage *image;
	NSString *imageTitle;
}

@property (nonatomic, retain) UIImage *image;
@property (nonatomic, retain) NSString *imageTitle;

@end

iCodeBlogXMLElement.m

@synthesize image;
@synthesize imageTitle;

picture-241

picture-251

picture-261

picture-27

iCodeBlogXMLImagesViewController.h:

#import <UIKit/UIKit.h>
#import "iCodeBlogXMLElement.h"
#import "iCodeBlogXMLView.h"

@interface iCodeBlogXMLImagesViewController : UIViewController
{
	IBOutlet UIScrollView *scrollview;

	NSXMLParser *parser;
	NSMutableString *currentAttribute;
	NSMutableArray *xmlElementObjects;

	iCodeBlogXMLElement *tempElement;
}

@property (nonatomic, retain) IBOutlet UIScrollView *scrollview;

@property (nonatomic, retain) NSXMLParser *parser;
@property (nonatomic, retain) NSMutableString *currentAttribute;
@property (nonatomic, retain) NSMutableArray *xmlElementObjects;

@property (nonatomic, retain) iCodeBlogXMLElement *tempElement;

-(void)layoutSubview;

@end

iCodeBlogXMLImagesViewController.m

@implementation iCodeBlogXMLImagesViewController

@synthesize scrollview;
@synthesize parser;
@synthesize currentAttribute;
@synthesize xmlElementObjects;
@synthesize tempElement;

...

- (void)viewDidLoad
{
    [super viewDidLoad];

	xmlElementObjects = [[NSMutableArray alloc] init];

	parser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://losectrl-gaincommand.com/iCodeBlogHelper/Tutorial3/iCodeBlogImageXML.xml"]];
	[parser setDelegate:self];
	[parser parse];
}

...

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{

}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{

}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{

}

picture-281

picture-291

picture-301

picture-311

iCodeBlogXMLImagesViewController.m

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
	if(![elementName compare:@"PictureInfo"])
	{
		tempElement = [[iCodeBlogXMLElement alloc] init];
	}

	else if(![elementName compare:@"imageURL"])
	{
		currentAttribute = [NSMutableString string];
	}

	else if(![elementName compare:@"imageTitle"])
	{
		currentAttribute = [NSMutableString string];
	}
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
	if(![elementName compare:@"PictureInfo"])
	{
		[xmlElementObjects addObject:tempElement];
	}

	else if(![elementName compare:@"imageURL"])
	{
		NSURL *imageURL = [NSURL URLWithString:currentAttribute];
		NSData *data =  [NSData dataWithContentsOfURL:imageURL];
		UIImage *image = [[UIImage alloc] initWithData:data];

		[tempElement setImage:image];
	}

	else if(![elementName compare:@"imageTitle"])
	{
		NSLog(@"The image title is %@", currentAttribute);
		[tempElement setImageTitle:currentAttribute];
	}

	else if(![elementName compare:@"Pictures"])
	{
		[self layoutSubview];
	}
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
	if(self.currentAttribute)
	{
		[self.currentAttribute appendString:string];
	}
}

picture-321

iCodeBlogXMLImagesViewController.m

-(void)layoutSubview
{
	CGRect workingFrame;

	workingFrame.origin.x = 0;
	workingFrame.origin.y = 0;
	workingFrame.size.height = 480;
	workingFrame.size.width = 320;

	iCodeBlogXMLView *myView;

	for(iCodeBlogXMLElement *element in [self xmlElementObjects])
	{
		myView = [[iCodeBlogXMLView alloc] initWithFrame:workingFrame];

		NSLog(@"Element title is: %@", [element imageTitle]);

		NSArray *topLeveObjects = [[NSBundle mainBundle] loadNibNamed:@"iCodeBlogXMLView" owner:nil options:nil];

		for(id currentObject in topLeveObjects)
		{
			if([currentObject isKindOfClass:[iCodeBlogXMLView class]])
			{
				myView = (iCodeBlogXMLView *)currentObject;
			}
		}

		[[myView imageView] setImage:[element image]];
		[[myView title] setText:[element imageTitle]];
		[myView setFrame:workingFrame];

		[scrollview addSubview:myView];

		workingFrame.origin.x = workingFrame.origin.x + 320;
	}

	workingFrame.size.width = workingFrame.origin.x;
	[scrollview setContentSize:workingFrame.size];

	workingFrame.origin.x = 0;
	workingFrame.origin.y = 0;
	workingFrame.size.width = 320;
	workingFrame.size.height = 480;
}

picture-33

iCodeBlogXMLImagesViewController.m

	parser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://losectrl-gaincommand.com/iCodeBlogHelper/Tutorial3/iCodeBlogImageXMLB.xml"]];
This entry was posted in Interface Builder, Uncategorized, objective-c and tagged , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

42 Comments

  1. Posted June 19, 2009 at 9:32 pm | Permalink

    Great Tutorial Dude. Only one tip you kinda go a little to fast. Other then that I love your tuts man !

  2. Posted June 19, 2009 at 10:51 pm | Permalink

    This tutorial is awesome.
    Thanks for the source code,

    Could you post the source code of the “Custom UItableViewCell Using IB” tutorial.

    Thanks.

  3. Posted June 20, 2009 at 2:23 pm | Permalink

    William,

    Updated the Custom UITableViewCell Using IB post with the source. Thanks for reading!

  4. Posted June 20, 2009 at 4:53 pm | Permalink

    GREAT!
    Thanks a lot, keep up the good work.

    Thanks
    William Muro

  5. Posted June 21, 2009 at 3:54 am | Permalink

    really a great tutorial. exactly what i need !

  6. Jake
    Posted June 21, 2009 at 11:48 am | Permalink

    I was curious if there was an easy way to speed up the parsing of the XML data. Also how hard would it be to use this same general layout of the app but using a .plist file to load the images and titles? Would you be able to parse an XML file with categories into a UITableView and then when a category is selected be able to transition to the proper view with that categories XML data?

  7. Nuri
    Posted June 22, 2009 at 6:10 am | Permalink

    Hey Collin,

    I am new to xcode, your tutorials really gave me a good start to understand how xcode works.

    Many thanks

    Nuri

  8. Fernando
    Posted June 22, 2009 at 11:05 pm | Permalink

    This was yet another excellent tutorial.

    I have one issue with it though, but I don’t know if anyone else here can test. While this does properly work in the simulator, when I actually attempt to compile it to the device I get a warning in the console, and the screen does not seem to fill. This is fully functioning on the simulator however.

    This is on a second generation iPod Touch that has a wifi connection available. All I get is a grey screen.

    Here is the log:

    [Session started at 2009-06-23 01:04:09 -0400.]
    GNU gdb 6.3.50-20050815 (Apple version gdb-1119) (Thu May 14 05:35:37 UTC 2009)
    Copyright 2004 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type “show copying” to see the conditions.
    There is absolutely no warranty for GDB. Type “show warranty” for details.
    This GDB was configured as “–host=i386-apple-darwin –target=arm-apple-darwin”.tty /dev/ttys001
    sharedlibrary apply-load-rules all
    Loading program into debugger…
    Program loaded.
    target remote-mobile /tmp/.XcodeGDBRemote-199-35
    Switching to remote-macosx protocol
    mem 0×1000 0x3fffffff cache
    mem 0×40000000 0xffffffff none
    mem 0×00000000 0x0fff none
    run
    Running…
    [Switching to thread 10755]
    [Switching to thread 10755]
    (gdb) continue
    warning: Unable to read symbols for “”/Users/admin/Development Files/iCodeBlogXMLImages/build/Debug-iphoneos”/iCodeBlogXMLImages.app/iCodeBlogXMLImages” (file not found).
    warning: Unable to read symbols for “”/Users/admin/Development Files/iCodeBlogXMLImages/build/Debug-iphoneos”/iCodeBlogXMLImages.app/iCodeBlogXMLImages” (file not found).

  9. Fernando
    Posted June 22, 2009 at 11:13 pm | Permalink

    actually, nevermind. I figured it out. I was using the wrong URL for this, and somehow it didn’t get refreshed on my simulator until I ‘touched’ everything again.

  10. Fernando
    Posted June 22, 2009 at 11:17 pm | Permalink

    On a side note, if anyone noticed the problem with the scroll view, it was buggy because the view size was set to 320×480, instead of what it should be. I forget how much the top bar takes up, I think there is a constant for this.

  11. Jake
    Posted June 23, 2009 at 10:16 am | Permalink

    All you need to do for that is set the UIScrollBarHidden option in the plist and set the value to type Boolean and check the checkbox and it will take the menu bar away.

  12. Brian Kendig
    Posted June 24, 2009 at 12:15 pm | Permalink

    Thank you for the terrific tutorial! I’m having trouble, though; my app crashes on this line:

    NSArray *topLeveObjects = [[NSBundle mainBundle] loadNibNamed:@”iCodeBlogXMLView” owner:nil options:nil];

    The error is “[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key imageView.”

    If I ‘unhook’ the imageView connection in Interface Builder, so that the ‘imageView’ outlet isn’t connected to my UIImageView object, then I get the same error complaining about ‘title’. If I unhook the title, so that neither outlet is connected, then the nib loads and the app runs (but doesn’t do anything interesting). What am I doing wrong?

    Thank you for your help!

  13. Brian Kendig
    Posted June 24, 2009 at 12:18 pm | Permalink

    Whups, the web page ate part of the error message. If I replace lessthan-greaterthan with parentheses, the error starts out:

    [(NSObject 0xd54eb0) setValueForUndefinedKey:]: …

    Of course an NSObject isn’t going to understand the key ‘imageView’, but I don’t understand why it’s trying to send that key to an NSObject instead of to an iCodeBlogXMLView.

  14. Brian Kendig
    Posted June 24, 2009 at 12:56 pm | Permalink

    I figured it out! With the help of your source code that I downloaded.

    The problem was that I was hooking up ‘title’ and ‘imageView’ from File’s Owner. I had to unhook those, then hook the same two things from I Code BlogXML. (Weird way Interface Builder has of representing names.) Now the app works fine!

  15. Ramu
    Posted June 25, 2009 at 9:55 pm | Permalink

    Great tutorial dude .
    if possible please post a tutorial how to parse a local XML file on the desktop and display the data in the tableView

    Thanks dude for a great tutorial

  16. Jetzdax
    Posted June 26, 2009 at 1:10 am | Permalink

    Great tutorial. Quite a lot to take but it is like a good book, you can always go back and watch again to absorb more if need.

    With the scroll view looking a bit buggy, I think it is because the size is set at 320×480 in the code but in the XIB, the status bar is left on, hence your UIView is at 320×460.

    It can be fixed by setting the “Status Bar” in Interface Builder to “None” instead of gray, and subsequently in the applicationDidFinishLaunching method, add the line:

    [[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];

    Just wanted to contribute :-)

  17. Roland Combes
    Posted June 29, 2009 at 8:15 am | Permalink

    As people have mentioned, the easiest way to fix the unwanted vertical scrolling is by changing the following lines at the top and bottom of the layoutSubView procedure in iCodeBlogXMLImagesViewController.m…

    workingFrame.size.height = 460;

    One problem I’m having is that the first URL works fine (albeit slowly) but the second one (http://losectrl-gaincommand.com/iCodeBlogHelper/Tutorial3/iCodeBlogImageXMLB.xml) causes the iPhone simulator to hang for a long period and then close the iCodeXMLImages app.

    I can’t seem to determine why this is although I am using 2.2.1 (haven’t yet downloaded the 3.0 package due to failed downloads).

    Excellent tutorial though. Thanks.

  18. Nandakumar
    Posted July 2, 2009 at 4:03 am | Permalink

    Hi,
    Great tutorial man….

    I have gone through most of your tutorials…find them very helpful in solving my issues..
    I have a doubt, is it possible to create an xml file in Iphone… i used NSXmlDocument to generate it in simulator, but that doesn’t work on iphone???

    Any help will be really helpful?

  19. Fernando
    Posted July 6, 2009 at 11:55 pm | Permalink

    @Roland Combes

    I had this exact problem when I took this application to an actual device. The issue is that the bulk of the work is done when the application is just finishing loading, and hasn’t fully launched.

    What occurs is the program times out during its initial load sequence (there is some sort of time limit for the initial loading of a program – although I have not figured out what exactly controls it). This time also seems to vary at every launch (it takes longer to time out sometimes, and less time to timeout other times).

    This ‘timeout’ occurs only if you are not running the program from xCode, but are running a precompiled version on your iPhone/iPod or I guess simulator (haven’t actually verified).

    The major lag occurs because the iPhone is accessing all the data, one image at a time, at launch time over the internet (which is not incredibly fast). I imagine this problem would be non-existent if you already had the xlm and images on your iPod touch, but then you would not be parsing/referncing an NSUrl (part of the point of this tutorial).

    Also, this problem only happens because this delay occurs during load time, which would never occur on a real program (since you will want to optimize your code so that it launches almost immediately, and only fetches data from the internet if it has to).

    The simple way to figure out what exactly is occuring is to try to monitor all the messages that get sent to the appDelegate. I have as of yet figured out how to do this while the application is not attached to xcode.

  20. Daniel
    Posted July 8, 2009 at 5:40 pm | Permalink

    I guess the xml file used for this article was removed….

  21. Alexander
    Posted July 13, 2009 at 1:27 am | Permalink

    Thanx for great tutorials.

    But almost all the source and videos are missing/dead links.

    Is there any possibility for getting ‘em linked up again?

  22. richard
    Posted July 13, 2009 at 7:55 am | Permalink

    I’d really like to watch the screencast.
    Can you put it back on-line?

  23. Holiday
    Posted July 14, 2009 at 8:54 pm | Permalink

    This is a great tutorial. I also need the XML file to complete the tutorial. Did anyone happen to download it?

  24. Posted July 24, 2009 at 6:29 am | Permalink

    I’d also really like to have look at this tutorial. Would you mind putting the source and tut back online please.

    Many thanks and keep up the excellent site.

  25. Andrey
    Posted August 1, 2009 at 12:36 am | Permalink

    Great Tutorials!
    Please fix broken links!

  26. Ipodmail
    Posted August 1, 2009 at 9:28 pm | Permalink

    BROKEN LINKS PLEASE FIX

  27. Jeremy
    Posted August 1, 2009 at 10:55 pm | Permalink

    One question – with this line:

    myView = [[iCodeBlogXMLView alloc] initWithFrame:workingFrame];

    Where does it get released? Especially if it’s being allocated multiple times in a for loop won’t this lead to big memory leaks? Thanks.

  28. Posted August 7, 2009 at 1:53 am | Permalink

    Super tutorial man!

    Can anyone please upload the files somewhere since the links are broken? :(

  29. Shogan
    Posted August 18, 2009 at 4:10 am | Permalink

    Hey guys, I know the links are broken, but by using clues and google you can re-create what you are missing. I completed this tutorial the other night – screencast can be found on vimeo.com, and if you want XML data, you can use my XML I created for this: just put the following link in place of the ctrl-alt-command URL…

    http://dl.getdropbox.com/u/450727/sean.xml

    At the moment I only have two pics loaded into it, but it works fine and you can scroll back and forward between the two images. It also loads a bit quicker than having 10 pics in there!

    Let me know if it works ok in your tutorial apps :)

    All I did was look at the screenshot in the screencast, and re-created my own XML using the info I could make out in the screenshots.

  30. Sven
    Posted August 19, 2009 at 12:21 am | Permalink

    Nice Tutorial, but would be great to offer a working link for the source code.

    Thank you

  31. Amar
    Posted August 23, 2009 at 5:31 am | Permalink

    Please update the link to Source Code for Using NSXMLParser to Pull UIImages From the Web (this tutorial)

  32. Pete
    Posted August 27, 2009 at 1:19 am | Permalink

    Great tutorial, it was just what i was looking for.

    Can someone update the link though so it can be tested in the simulator.

  33. Posted September 6, 2009 at 6:30 pm | Permalink

    For those who want to see this code in action, download the sample. Even though the link is history, it’s pretty easy to make and post your own test .xml file and a few images on a web server. If you use the same xml layout as is shown in the tutorial, you don’t have to change anything in the example code except that one URL near the beginning of iCodeBlogXMLImagesViewController.m

  34. fahad
    Posted October 5, 2009 at 12:03 am | Permalink

    do is support image of any resolution ?

  35. madmagi
    Posted November 16, 2009 at 8:05 pm | Permalink

    Thanks for a great tutorial. I have used it as a baseline for an app i was working on. One problem i am running into however i could use some help on. If the first image is smaller than the area, i see some of the next image bleeding over on the right side – how do i resolve this?

    Example
    IMAGEIMAGEXXXX

    IMAGEIMAGE is the first image, the XXXX is part of the second image. Then when i scroll to the second image, there is part of the 3rd image on the right of that one as well.

    The final image if there is 3, is fine.

    Thanks

  36. Raj
    Posted January 9, 2010 at 11:21 am | Permalink

    This is great tutorial. I have a problem. My NSXML parser method are not started. When I try to debugg It never trigger that event. Any help please advise.

  37. Gabriela
    Posted February 24, 2010 at 2:05 pm | Permalink

    Excellent tutorial …

    could help me with a problem?
    my application is closed in the process of loading parser ten images.

    any help thank you very much ..

  38. Posted February 25, 2010 at 2:05 pm | Permalink

    awesome tutorials. is there a page where i can find all of the tutorials you’ve done so far?

  39. Chris
    Posted April 13, 2010 at 10:27 am | Permalink

    I’m using Xcode 3.1 and I’m not seeing a Scroll View in Interface Builder. Is this something on my end I’m missing, or are scroll views handled differently since this tutorial was first created?

  40. Posted May 30, 2010 at 9:11 pm | Permalink

    Thank you so much for this tutorial. I’m just getting started with NSXMLParser and I’ve been racking my brain over how it works until now.

    Sir, my imaginary hat is off to you.

  41. Jean
    Posted June 4, 2010 at 6:24 am | Permalink

    I think this line :
    ” myView = [[iCodeBlogXMLView alloc] initWithFrame:workingFrame]; ”
    in function -(void)layoutSubview of iCodeBlogXMLImagesViewController.m
    should be deleted, because it causes memory leaks .

    (myView is provided by loadNibNamed)

    Thanks for this very good tutorial

  42. MIghtyMike
    Posted August 1, 2010 at 12:11 pm | Permalink

    I only get a screen that says testing.

2 Trackbacks

  1. [...] Using NSXMLParser to Pull UIImages From the Web | iCodeBlog "But the general idea of the app we will build is that it will use an XML file online to get the URL and title of a given picture. For each URL and Title pair a view will be created with a UIImageView showing the image and a UILabel showing the title. Each of these views will be placed in a UIScrollView to flip through, like th functinoality of the Photos app." (tags: objective-c iphone app apps code development objectivec NSXMLParser XML) [...]

  2. [...] some online tutorials use them as a quick-and-dirty way to load resources from the network (for example this one on iCodeBlog), and I have myself seen production code using this [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">