GIFs don't animate when using NSThread - objective-c

I'm writing an application in Objective C and Cocoa for Mac OS X that loads GIFs from an external source and displays them on screen. The user searches for a term, GIFs are downloaded and placed into NSImageViews, and then those views are displayed in a scroll view.
Earlier, the GIFs were animated as expected. I then tried to use an NSThread to do the loading of the GIFs and adding to the scroll view separate from the main thread. Here is the method that is called in the thread:
- (void)threading:(id)obj
{
NSURL *url = [NSURL URLWithString: #"URL HERE"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setURL:url];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSError *error;
NSURLResponse *response;
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error] options:NSJSONReadingMutableLeaves error:nil];
NSArray *gifs = [data objectForKey:#"data"];
for (int i = 0; i < 1; i++) { // try to load 1 gif
NSString *currentGifURL = #"whatever";
NSImageView *imgView = [[NSImageView alloc] initWithFrame:CGRectMake(10, 1820-100*i, 150, 120)];
// I tried using these 2 lines, still didn't work
//[imgView setAnimates:YES]; [imgView setImageScaling:NSScaleNone];
NSURL *imageURL = [NSURL URLWithString:currentGifURL];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
NSImage *image = [[NSImage alloc] initWithData:imageData];
imgView.image = image;
[_scrollView.documentView addSubview:imgView];
}
[_progressIndicator stopAnimation:self];
}
I later call
[NSThread detachNewThreadSelector:#selector(threading:) toTarget:self withObject:nil];
To create the thread. The images appear on screen, but only the first frame is displayed—they're not animated. Literally replacing the thread initialization with the code from inside the thread renders the same view, except the GIFs are animated. Is there something about threads that would prevent the GIFs from animating?
Thanks!

NSImageView is not threadsafe. use - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
- (void)threading:(id)obj
{
NSURL *url = [NSURL URLWithString: #"URL HERE"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setURL:url];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSError *error;
NSURLResponse *response;
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error] options:NSJSONReadingMutableLeaves error:nil];
NSArray *gifs = [data objectForKey:#"data"];
for (int i = 0; i < 1; i++) { // try to load 1 gif
NSString *currentGifURL = #"whatever";
// I tried using these 2 lines, still didn't work
//[imgView setAnimates:YES]; [imgView setImageScaling:NSScaleNone];
NSURL *imageURL = [NSURL URLWithString:currentGifURL];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
NSImage *image = [[NSImage alloc] initWithData:imageData];
[self performSelectorOnMainThread:#selector(LoadImageView:) withObject:image waitUntilDone:NO];
}
[_progressIndicator stopAnimation:self];
}
-(void)LoadImageView : (NSImage *)image
{
NSImageView *imgView = [[NSImageView alloc] initWithFrame:CGRectMake(10, 1820-100*i, 150, 120)];
imgView.image = image;
[_scrollView.documentView addSubview:imgView];
}

Related

can't download image from web and how to check image from web

So I have this method to download an image from imgur.com as shown below:
- (void)getImageForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"i.imgur.com/%#.jpg",
[self.IDArray objectAtIndex:indexPath.row]]];
NSData * imageData = [[NSData alloc] initWithContentsOfURL:url];
self.imageTest = [UIImage imageWithData: imageData];
}
and then log the size of the data with this:
NSLog(#"%lx", (unsigned long)imageData.length);
but the size of the image in the log says
0
previously I use this asynchronous method:
- (void)getImageForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"i.imgur.com/%#.jpg",
[self.IDArray objectAtIndex:indexPath.row]]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:urlRequest
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
UIImage *imageMain = [UIImage imageWithData:data];
self.imageTest = [[UIImage alloc] init];
self.imageTest = [self imageWithImage:imageMain forRowAtIndexPath:indexPath];
}];
self.imageTest = [UIImage imageWithData: imageData];
}
but the log also says 0
yes the url exist. I have log it in another another method it is: i.imgur.com/EXtwoxT
What did I do wrong? how do I check that the image has been downloaded properly?

can't download image from web

So I have this method to download an image from imgur.com as shown below:
- (void)getImageForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"i.imgur.com/%#.jpg",
[self.IDArray objectAtIndex:indexPath.row]]];
NSData * imageData = [[NSData alloc] initWithContentsOfURL:url];
self.imageTest = [UIImage imageWithData: imageData];
}
and then log the size of the data with this:
NSLog(#"%lx", (unsigned long)imageData.length);
but the size of the image in the log says
0
previously I use this asynchronous method:
- (void)getImageForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"i.imgur.com/%#.jpg",
[self.IDArray objectAtIndex:indexPath.row]]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:urlRequest
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
UIImage *imageMain = [UIImage imageWithData:data];
self.imageTest = [[UIImage alloc] init];
self.imageTest = [self imageWithImage:imageMain forRowAtIndexPath:indexPath];
}];
self.imageTest = [UIImage imageWithData: imageData];
}
but the log also says 0
yes the url exist. I have log it in another another method it is: i.imgur.com/EXtwoxT you can see for yourself
What did I do wrong? how do I check that the image has been downloaded properly?
EDIT :
for those who says it's the URL you can see my actual log below. you can copy&paste the URL in your browser to see if it exist (it does)
- (void)getImageForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"i.imgur.com/%#.jpg",
[self.IDArray objectAtIndex:indexPath.row]]];
NSLog(#"i.imgur.com/%#.jpg", [self.IDArray objectAtIndex:indexPath.row]);
//Asynchronous handler
// NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// [NSURLConnection sendAsynchronousRequest:urlRequest
// queue:[NSOperationQueue currentQueue]
// completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// UIImage *imageMain = [UIImage imageWithData:data];
// self.imageTest = [[UIImage alloc] init];
// self.imageTest = [self imageWithImage:imageMain forRowAtIndexPath:indexPath];
// NSLog(#"%lx", (unsigned long)imageData.length);
// }];
//Synchronous handler
NSData * imageData = [[NSData alloc] initWithContentsOfURL:url];
self.imageTest = [UIImage imageWithData: imageData];
NSLog(#"%lx", (unsigned long)imageData.length);
}
2015-01-06 07:44:26.564 Huckleberry[12733:361944] i.imgur.com/EXtwoxT.jpg
2015-01-06 07:44:26.600 Huckleberry[12733:361944] 0
First off, your code is missing a protocol for the URL -- NSURL can handle different protocols and doesn't just default to http. Prefix http:// to your URL and see if that gets you some data.
Secondly, that URL isn't actually the URL of the image -- I believe that URL will return the whole HTML imgur page, which is most likely not what you want (since you're trying to create a UIImage with the data).
Instead, try looking into the Imgur API (https://api.imgur.com) -- there's even a link on that page to an example Obj-C library (https://github.com/geoffmacd/ImgurSession)

converting NSData to UIImage - working with NSURLRequest

I've been working with AFHTTPRequestOperationManager calling my service that return an image and my code looked like this:
NSString *baseURLString = #"http://get_image/";
#try {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:baseURLString
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *imageStr = responseObject[0];
if([imageStr isKindOfClass:[NSNull class]]==NO)
{
NSData *imageData = [NSData dataWithBase64EncodedString:imageStr];
UIImage *image = [UIImage imageWithData:imageData];
self.myImage = (image==nil)? [UIImage imageNamed:#"noPhoto"]: image;
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
self.myImage = [UIImage imageNamed:#"noPhoto"];
}];
}
#catch (NSException *exception) {
NSLog(#"exception %#", exception);
}
since AFHTTPRequestOperationManager is async and I need a sync call how can I complete this code to produce my image:
NSString *baseURLString = #"http://get_image/";
NSURLResponse *response;
NSError *error;
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:p_baseURLString] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30];
// Make synchronous request
NSData *imageRequest = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
???
UIImage *image = [UIImage imageWithData:imageData];
self.displayedApartment.exteriorImage = (image==nil)? [UIImage imageNamed:#"noPhoto"]: image;
This is what I've tried in place of ??? all resulted in image=nil
using the imageRequest data as is
converting the imageRequest to base64 with [[NSData alloc] initWithBase64EncodedData:imageRequest options:0];
converting it to string and back to NSData
NSData NSString *imageStr = [NSString stringWithUTF8String:[imageRequest bytes]];
NSData *imageData = [NSData dataWithBase64EncodedString:imageStr];
If I'm reading your code correctly, I think your variable names might be causing some trouble. Try replacing the following line:
NSData *imageRequest = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
with
NSData *imageData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
and then see what UIImage *image = [UIImage imageWithData:imageData]; gives you. Unless there has been an error in the request, I can't see a reason why image wouldn't be properly instantiated unless it didn't represent an image object.
Why not just display the image using the AFNetworking function setImageWithURL, it takes the URL of an image and sets the UIImageView to that image. Its a much simpler way of doing things if you only need to display it.
It looks something like this:
[imageView setImageWithURL:[NSURL URLWithString:p_baseURLString]];
In the header file you'll have something like this:
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
Its much faster as well.

iphone MBProgreeHUD Not worked When using POST method

When i will try to post some image or text from application to server that situation MBProgressHUD not worked. but without posting method its work perfectly. i am used below code.Please any one help me. thanks.
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.dimBackground = YES;
HUD.delegate = self;
NSString *urlRequest =[NSString stringWithFormat:#"URL"];
NSString *pStrLegalURLString =[urlRequestn stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [[NSURL alloc] initWithString:pStrLegalURLString];
NSMutableURLRequest *request1 = [NSMutableURLRequest requestWithURL:url];
[request1 setHTTPMethod:#"POST"];
NSData *returnData1 = [ NSURLConnection sendSynchronousRequest: request1 returningResponse: nil error: nil ];
NSString *returnString1 = [[NSString alloc] initWithData:returnData1 encoding: NSUTF8StringEncoding];
Try like this:
It will work, but your problem as i guess is because of sendSynchronousRequest which is a blocking call hence if the main thread hangs up you won't see any update in UI. So try to make such calls in background.
Try one of the two approaches as I see:
Approach 1: (send request in background using selectors and do UI update in main thread)
-(void)method1 {
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.dimBackground = YES;
HUD.delegate = self;
NSString *urlRequest =[NSString stringWithFormat:#"URL"];
NSString *pStrLegalURLString =[urlRequest stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [[NSURL alloc] initWithString:pStrLegalURLString];
NSMutableURLRequest *request1 = [NSMutableURLRequest requestWithURL:url];
[request1 setHTTPMethod:#"POST"];
// send request in background.
[self performSelectorInBackground:#selector(method2) withObject:nil];
}
-(void)method2 {
NSData *returnData1 = [ NSURLConnection sendSynchronousRequest: request1 returningResponse: nil error: nil ];
NSString *returnString1 = [[NSString alloc] initWithData:returnData1 encoding: NSUTF8StringEncoding];
[self performSelectorOnMainThread:#selector(method3) withObject:nil waitUntilDone:NO];
}
-(void)method3
{
// update ui in main thread.
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
}
Approach 2: Use Dispatch_Async and Dispatch_Sync
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void){
// Do background work here
dispatch_sync(dispatch_get_main_queue(), ^(void){
// Update UI here
});
});

iphone SDK: How to post data to a url?

This may be a duplicate question but i could not find my answer when searching. So, How do i post data to a url? Heres what i got so far:
NSString *url = #"https://localhost/login.php";
NSURL *urlr = [NSURL URLWithString:url];
NSMutableURLRequest *urlre = [[NSMutableURLRequest alloc] init];
[urlre setURL:[NSURL URLWithString:url]];
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSString *user = [defs stringForKey:#"User"];
NSString *pass = [defs stringForKey:#"Pass"];
NSInteger *version = [defs integerForKey:#"Version"];
NSString *bodyData = [[NSString alloc] initWithFormat:#"user=%#&password=%#&version=%d",user,pass,version];
NSData *body = [bodyData dataUsingEncoding:NSASCIIStringEncoding];
NSURLResponse *response = nil;
NSError *error = nil;
[urlre setHTTPMethod:#"POST"];
[urlre setValue:[[NSString alloc] initWithFormat:#"%d",[body length]] forHTTPHeaderField:#"Content-Length"];
[urlre setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[urlre setHTTPBody:body];
NSData *dataThis = [NSURLConnection sendSynchronousRequest:urlre returningResponse:&response error:&error];
if(dataThis)
{
NSLog(#"Connect Success");
} else {
NSLog(#"%#",[error localizedDescription]);
}
Is the above correct? In my
-(void) connection:(NSURLConnection*)connection didReceiveData:(NSData *)data
event, I get nothing. Even in the didFinishLoading it gets nothing with NSLog. Please help.
Have you set a delegate for your request?
Why don't you have a look at using a framework like ASIHTTPRequest, makes things so simple. Check it out http://allseeing-i.com/ASIHTTPRequest/