I have a loop set up that downloads a series a images which I will later use for to animate using the animationImages property of UIImageView. I would like to know when all the blocks inside my loops have finished executing so I could begin the animation, and was wondering how I may be able to tell when they are finished completing? Thanks!
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
}];
}
//When I know all the blocks have finished downloading, I will then to animate the downloaded images.
Edit: having issue with Error -999
I am encountering the following issue when executing the code in the provided answer: Domain=NSURLErrorDomain Code=-999 "The operation couldn’t be completed. (NSURLErrorDomain error -999.)"
A quick search reveals that Error -999 means "another request is made before the previous request is completed" ... which is certainly the case here since I am making several requests in quick succession. The recommended fix suggested here didn't work for me as it will only successfully download one UIImage (the last one requested) , with the previous ones failing. I was wondering if there is workaround here or in AFNetworking that I ought to consider? Thanks!
Edit 2: working code based on #David's solution
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:imageRequest];
requestOperation.responseSerializer = [AFImageResponseSerializer serializer];
dispatch_group_enter(group);
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Response: %#", responseObject);
UIImage *retrivedImage = (UIImage *)responseObject;
[self.downloadedUIImages addObject:retrivedImage];
dispatch_group_leave(group);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Image error: %#", error);
dispatch_group_leave(group);
}];
[requestOperation start];
counter ++;
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(#"Horray everything has completed");
NSLog(#"What is here %#", self.downloadedUIImages);
NSLog(#"Done");
});
Create a dispatch group, in the for loop enter the group, in the completion block leave the group. Then you can use dispatch_group_notify to find out when all blocks have completed:
dispatch_group_t group = dispatch_group_create();
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
dispatch_group_enter(group);
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
dispatch_group_leave(group);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
dispatch_group_leave(group);
}];
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// do your completion stuff here
});
Count how many you've completed. The challenging part is making it thread safe. I recommend creating an atomic counter class for that.
Generic solution!
+ (void)runBlocksInParallel:(NSArray *)blocks completion:(CompletionBlock)completion {
AtomicCounter *completionCounter = [[AtomicCounter alloc] initWithValue:blocks.count];
for (AsyncBlock block in blocks) {
block(^{
if ([completionCounter decrementAndGet] == 0) {
if (completion) completion();
}
});
}
if (blocks.count == 0) {
if (completion) completion();
}
}
NSMutableArray *asyncBlocks = [NSMutableArray array];
for (PFObject *pictureObject in objects){
[asyncBlocks addObject:^(CompletionBlock completion) {
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
} completion:completion];
}];
}
[BlockRunner runBlocksInParallel:[asyncBlocks copy] completion:^{
//Do your final completion here!
}];
Set up a property and initialize it to the number of cycles - objects.count. In the completion of the block, lower the number down. When you reach zero, you are done.
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
if([[objects lastObject] isEqual:pictureObject]) {
[self animateImages];
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
if([[objects lastObject] isEqual:pictureObject]) {
[self animateImages];
}
}];
}
- (void)animateImages {
//do animation here.
}
Related
I'm trying to get an image asynchronously from an url with AFNetworking 2.0
My problem is that neither success nor failure are called
I've checked my URL in a browser so the problem is not here
UIImageView *imgv = [[UIImageView alloc] init];
[imgv setImageWithURLRequest:myURL
placeholderImage:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
/*some code*/
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
/*some code*/
];
When I look deeper inside setImageWithUrlRequest:placeholderImage:success:failure
__weak __typeof(self)weakSelf = self;
self.af_imageRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
self.af_imageRequestOperation.responseSerializer = self.imageResponseSerializer;
[self.af_imageRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[urlRequest URL] isEqual:[strongSelf.af_imageRequestOperation.request URL]]) {
if (success) {
success(urlRequest, operation.response, responseObject);
} else if (responseObject) {
strongSelf.image = responseObject;
}
if (operation == strongSelf.af_imageRequestOperation){
strongSelf.af_imageRequestOperation = nil;
}
}
[[[strongSelf class] sharedImageCache] cacheImage:responseObject forRequest:urlRequest];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[urlRequest URL] isEqual:[strongSelf.af_imageRequestOperation.request URL]]) {
if (failure) {
failure(urlRequest, operation.response, error);
}
if (operation == strongSelf.af_imageRequestOperation){
strongSelf.af_imageRequestOperation = nil;
}
}
}];
My code goes trought [self.af_imageRequestOperation setCompletionBlockWithSuccess:^( AFHTTPRequestOperation *operation, id responseObject) {
with success but i've noticed that __strong __typeof(weakSelf)strongSelf = weakSelf; are both nil
Any idea?
Your imgv is never retained so it will be released after current scope so in your block weakSelf will be release when image is successfuly downloaded so thats why you are getting nil.
I have two methods that are running their code in background, and method1 triggers method2 as follows:
+(void)insertAllDataInDatabase{
NSLog(#"1");
NSString *url=#"http://localhost/kalimat/get_all_artists.php";
//NSLog(#"url %#",url);
NSURL *urlChannels= [ NSURL URLWithString:url];
NSURLRequest *request = [NSURLRequest requestWithURL:urlChannels];
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request,
NSHTTPURLResponse *response,
id JSON) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
{
NSMutableArray *arrayOfJson=JSON;
for (int i=0; i<[arrayOfJson count]; i++) {
NSLog(#"2");
NSMutableDictionary *songDico=[arrayOfJson objectAtIndex:i];
NSString *artist=[songDico objectForKey:#"artist"];
[self getArtistSongs:artist];
}
});
NSLog(#"6");
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response,
NSError *error, id JSON) {
//DLog(#"Request Failure Because %#",[error userInfo]);
}];
[operation start];
}
+(void)getArtistSongs:(NSString*)artist {
NSLog(#"3");
LKDBHelper* globalHelper = [LKDBHelper getUsingLKDBHelper];
NSMutableArray *arrayOfSongs=[[NSMutableArray alloc]init];
artist = [artist stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//DLog(#"artisttt %#",artist);
NSString *url=[NSString stringWithFormat:#"%#?artist=%#", #"http://localhost/kalimat/get_kalimat.php",artist];
url = [url stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
//NSLog(#"url %#",url);
NSURL *urlChannels= [ NSURL URLWithString:url];
NSURLRequest *request = [NSURLRequest requestWithURL:urlChannels];
[LKDBHelper clearTableData:[Song class]];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request,
NSHTTPURLResponse *response,
id JSON) {
NSMutableArray *arrayOfJson=JSON;
for (int i=0; i<[arrayOfJson count]; i++) {
NSLog(#"4");
NSMutableDictionary *songDico=[arrayOfJson objectAtIndex:i];
DCKeyValueObjectMapping *parser = [DCKeyValueObjectMapping mapperForClass: [Song class]];
Song *song = [parser parseDictionary:songDico];
song.artist=artist;
[arrayOfSongs addObject:song];
//DLog(#"inserting...");
[globalHelper insertToDB:song];
//DLog(#"getting lyrics");
//[self getLyricsWhereArtist:artist andSong:song.song];
//[[NSNotificationCenter defaultCenter] postNotificationName:#"AllArtistsSongs" object:arrayOfSongs];
}
NSLog(#"5");
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response,
NSError *error, id JSON) {
DLog(#"Request Failure Because %#",[error userInfo]);
}];
[operation start];
});
}
Basing on the NSLogs, I want to have :
1
2
3
4
4
4
4
...
5
6
But I'm having:
1
6
2
3
2
3
2
3
2
3
...
Is there a way to order the execution of those methods?
Thank you very much for your help.
You're already calling getArtistSongs: from a background thread. If you want those to run serially, just remove the dispatch_async call from that method. You'd also need to make those requests synchronously; I haven't used AFNetworking so I don't know if that's available or how to do it.
This will work without blocking the main thread, because your calls to getArtistSongs: come from the block that's running on the background thread:
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
// All this code runs in the background.
NSMutableArray *arrayOfJson=JSON;
for (int i=0; i<[arrayOfJson count]; i++) {
NSLog(#"2");
NSMutableDictionary *songDico=[arrayOfJson objectAtIndex:i];
NSString *artist=[songDico objectForKey:#"artist"];
[self getArtistSongs:artist];
}
// All code above runs in the background.
});
The 6, of course, will still print immediately after the 1. If you need code to run last of all, it goes inside the block, after the for loop of songDiscos, possibly wrapped in a dispatch_async to the main thread.
I have the following code inside a class (static method) which I call to get data from an API. I decided to make this a static method just so I can reuse it on some other parts of the app.
+ (NSArray*) getAllRoomsWithEventId:(NSNumber *)eventId{
NSURL *urlRequest = [NSURL URLWithString:[NSString stringWithFormat:#"http://blablba.com/api/Rooms/GetAll/e/%#/r?%#", eventId, [ServiceRequest getAuth]]];
NSMutableArray *rooms = [[NSMutableArray alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:urlRequest];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"Response of getall rooms %#", JSON);
NSArray *jsonResults = (NSArray*)JSON;
for(id item in jsonResults){
Room* room = [[Room alloc]init];
if([item isKindOfClass:[NSDictionary class]]){
room.Id = [item objectForKey:#"Id"];
room.eventId = [item objectForKey:#"EventId"];
room.UINumber = [item objectForKey:#"RoomUIID"];
[rooms addObject:room];
}
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON){
NSLog(#"Error");
}];
[operation start];
[operation waitUntilFinished];
return rooms;
}
Now my issue is, whenever I call this in a ViewController (ViewDidLoad method). The static method will run till the end and will return null on the rooms, but the Nslog will display the "Success" block Nslog a few seconds after. Now I understand that this is asynchronous so it doesn't wait for the success block to execute before it reaches the "return rooms;" line. With all that said, I need some advice as to how to handle this, like maybe a progress bar or something like that? Or something that delays it? I'm not really sure if that's the reight way or if it is, I am not sure how to do it.
Any advice is very much appreciated. Thank you!
AFNetworking is built around asynchronicity—starting a request, and then executing some piece of code once that request has finished.
waitUntilFinished is an anti-pattern, which can block the user interface.
Instead, your method should have no return type (void), and have a completion block parameter that returns the serialized array of rooms:
- (void)allRoomsWithEventId:(NSNumber *)eventId
block:(void (^)(NSArray *rooms))block
{
// ...
}
See the example app in the AFNetworking project for an example of how to do this.
You can write your method following way:
+ (void) getAllRoomsWithEventId:(NSNumber *)eventId:(void(^)(NSArray *roomArray)) block
{
NSURL *urlRequest = [NSURL URLWithString:[NSString stringWithFormat:#"http://blablba.com/api/Rooms/GetAll/e/%#/r?%#", eventId, [ServiceRequest getAuth]]];
NSMutableArray *rooms = [[NSMutableArray alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:urlRequest];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"Response of getall rooms %#", JSON);
NSArray *jsonResults = (NSArray*)JSON;
for(id item in jsonResults){
Room* room = [[Room alloc]init];
if([item isKindOfClass:[NSDictionary class]]){
room.Id = [item objectForKey:#"Id"];
room.eventId = [item objectForKey:#"EventId"];
room.UINumber = [item objectForKey:#"RoomUIID"];
[rooms addObject:room];
}
}
block(rooms);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON){
NSLog(#"Error");
block(nil); //or any other error message..
}];
[operation start];
[operation waitUntilFinished];
}
you can call this method like followings:
[MyDataClass getAllRoomsWithEventId:#"eventid1":^(NSArray *roomArray) {
NSLog(#"roomArr == %#",roomArray);
}];
How do you download images in order with AFNetworking? An by "in order", I also mean executing the success blocks in order.
Initially I thought it would be enough to use a NSOperationQueue and set each AFImageRequestOperation as a dependency of the next one. Like this:
- (void) downloadImages
{
{ // Reset
[_downloadQueue cancelAllOperations];
_downloadQueue = [[NSOperationQueue alloc] init];
_images = [NSMutableArray array];
}
AFImageRequestOperation *previousOperation = nil;
for (NSInteger i = 0; i < _imageURLs.count; i++) {
NSURL *URL = [_imageURLs objectAtIndex:i];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
AFImageRequestOperation *operation = [AFImageRequestOperation
imageRequestOperationWithRequest:request
imageProcessingBlock:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[_images addObject:image];
NSLog(#"%d", i);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {}];
if (previousOperation) {
[operation addDependency:previousOperation];
}
previousOperation = operation;
[_downloadQueue addOperation:operation];
}
}
This prints i in order when the images are downloaded. However, when the requests are already cached, the success blocks are processed out of order. I suspect this is a NSOperation limitation, not AFNetworking.
Am I missing something?
As a workaround, I store the images in a dictionary and process them in order each time a request succeeds. Like this:
- (void) downloadImages
{
{ // Reset
[_downloadQueue cancelAllOperations];
_downloadQueue = [[NSOperationQueue alloc] init];
_images = [NSMutableArray array];
_imageDictionary = [NSMutableDictionary dictionary];
}
AFImageRequestOperation *previousOperation = nil;
for (NSInteger i = 0; i < _imageURLs.count; i++) {
NSURL *URL = [_imageURLs objectAtIndex:i];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
AFImageRequestOperation *operation = [AFImageRequestOperation
imageRequestOperationWithRequest:request
imageProcessingBlock:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[_imageDictionary setObject:image forKey:#(i)];
[self processImages];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {}];
if (previousOperation) {
[operation addDependency:previousOperation];
}
previousOperation = operation;
[_downloadQueue addOperation:operation];
}
}
- (void) processImages
{
for (NSInteger i = _images.count; i < _imageURLs.count; i++) {
UIImage *image = [_imageDictionary objectForKey:#(i)];
if (!image) break;
[_images addObject:image];
NSLog(#"%d", i);
}
}
This always prints i in order.
Your solution will work fine, here is another way to do it:
For the "perfect" UX you should issue all operations in parallel and process images by order as they come (don't wait if you don't have to).
(error handling is done differently here)
You could try this (untested, and you can better design the model [don't just use arrays like this]):
- (void) processImage:(UIImage*)image
{
//do something with the image or just [_images addObject:image]
}
- (void) downloadImages
{
{ // Reset
[_downloadQueue cancelAllOperations];
_downloadQueue = [[NSOperationQueue alloc] init];
}
__block NSMutableArray* queue = [[NSMutableArray alloc] initWithCapacity:[_imageURLs count]];
for (NSURL* url in _imageURLs) {
__block NSLock* lock = [[NSLock alloc] init];
__block NSMutableArray* container = [NSMutableArray new];
[lock lock];
[queue addObject:#[lock,container,url]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
void(^compBlock)(NSURLRequest *request,
NSHTTPURLResponse *response,
UIImage *image) = ^(NSURLRequest *request,
NSHTTPURLResponse *response,
UIImage *image)
{
[container addObject:image];
[lock unlock];
};
NSOperation *operation = [AFImageRequestOperation imageRequestOperationWithRequest:request
imageProcessingBlock:nil
success:compBlock
failure:compBlock];
[_downloadQueue addOperation:operation];
}
__block __weak id weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (NSArray* arr in queue) {
NSLock* lock = arr[0];
[lock lock];
NSMutableArray* container = arr[1];
if ([container count]) {
[weakSelf processImage:container[0]]; //might want to call this on main thread
} else {
//error on url = arr[2]
}
[lock unlock];
}
});
}
Neither the success or failure handler appears to be called when setImageWithURLRequest: is called on my UIImage object. SetImageWithURL does not set my image either. If I use setImageWithURL: placeholder: the placeholder is set but the image from the url never gets set.
Pardon my not posting code sooner. I have tried to use two methods (with AFNetworking) to asynchronously set my image views:
[_imageView setImageWithURL:[NSURL URLWithString:#"path/to/file"]];
[_imageView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.example.com/path/to/image.jpg"]] placeholderImage:[UIImage imageNamed:#"your_image_here.jpg"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
NSLog(#"Your image request succeeded!");
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Your image request failed...");
}];
I have tried having these triggered in viewDidLoad but the image view never loads.
After looking through the actual function declaration of setImageWithURLRequest: and it appears that neither the success or failure block is executed when I call it. I've placed NSLogs in the code to give you guys an idea of what happens:
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure
{
NSLog(#"Log shows");
[self cancelImageRequestOperation];
NSLog(#"Log shows");
UIImage *cachedImage = [[[self class] af_sharedImageCache] cachedImageForRequest:urlRequest];
NSLog(#"Log shows");
if (cachedImage) {
NSLog(#"Log does not show");
self.image = cachedImage;
self.af_imageRequestOperation = nil;
if (success) {
success(nil, nil, cachedImage);
NSLog(#"Log does not show");
}
} else {
NSLog(#"Log shows");
self.image = placeholderImage;
AFImageRequestOperation *requestOperation = [[AFImageRequestOperation alloc] initWithRequest:urlRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([[urlRequest URL] isEqual:[[self.af_imageRequestOperation request] URL]]) {
self.image = responseObject;
self.af_imageRequestOperation = nil;
NSLog(#"Log does not show");
}
if (success) {
success(operation.request, operation.response, responseObject);
NSLog(#"Log does not show");
}
[[[self class] af_sharedImageCache] cacheImage:responseObject forRequest:urlRequest];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if ([[urlRequest URL] isEqual:[[self.af_imageRequestOperation request] URL]]) {
self.af_imageRequestOperation = nil;
NSLog(#"Log does not show");
}
if (failure) {
failure(operation.request, operation.response, error);
NSLog(#"Log does not show");
}
}];
self.af_imageRequestOperation = requestOperation;
[[[self class] af_sharedImageRequestOperationQueue] addOperation:self.af_imageRequestOperation];
setImageWithURL: is a UIImageView category and cannot be used for setting a UIImage only used on a UIImageView.
[imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:#"placeHolderImage"]];
Here's the documentation: http://engineering.gowalla.com/AFNetworking/Categories/UIImageView(AFNetworking).html
Thanks for the help guys but like everyone on here noticed, there was no issue with my code. The issue was actually with regard to ARC. I had it turned off in my AFNetworking files. After turning it on, everything worked just fine.