How to show GET request in Label - ios

My get request works only in command line NSLog.
I need to show a data in Label, but it doesn't works.
-(void)getRequest{
NSURLSessionConfiguration *getConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *getSession = [NSURLSession sessionWithConfiguration: getConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
NSURL * getUrl = [NSURL URLWithString:#"http://localhost:3000/get"];
NSURLSessionDataTask * getDataTask = [getSession dataTaskWithURL:getUrl completionHandler:^(NSData *getData, NSURLResponse *getResponse, NSError *getError) {
if(getError == nil){
NSString * getString = [[NSString alloc] initWithData: getData encoding: NSUTF8StringEncoding];
[self.label setText:getString];// doesn't work!
NSLog(#"Data = %#",getString);}// it works!!
MainViewController*l=[[MainViewController alloc]init];
[l getRequest];
}
];
[getDataTask resume];
}

dataTaskWithURL is not working on the main-thread and that's necessary to update your UI.
if (getError == nil) {
NSString * getString = [[NSString alloc] initWithData: getData encoding: NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
[self.label setText: getString];
NSLog(#"Data = %#", getString);
});
}
This code will work fine for you.
You can also use:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self.label setText:getString];
}];
Real more here Why should I choose GCD over NSOperation and blocks for high-level applications?

While I'm not quite sure what the usage would be here...you are using #getString, which I think is the issue. You probably want to do something like:
[self.label setText:[NSString stringWithFormat:"Data = %#", getString];
That should have the same behavior as NSLog.

dispatch_async(dispatch_get_main_queue(), ^{
[self.label setText:someString];
});

Related

NSOperationOperationQueue cancelAllOperations method won't stop operations

How to cancel all operations in NSOperationQueue? I used cancelAllOperations method, but it didn't work, the NSOperationQueue is still calling server to upload photo.
I put every single connection on NSOperationQueue with loop.
- (void)sendingImage:(NSArray *)imgArray compression:(CGFloat)compression
{
hud = [MBProgressHUD showHUDAddedTo: self.view animated: YES];
hud.label.text = [NSString stringWithFormat: #"Waiting for Loading"];
[hud.button setTitle: #"Cancel" forState: UIControlStateNormal];
[hud.button addTarget: self action: #selector(cancelWork:) forControlEvents: UIControlEventTouchUpInside];
__block int photoFinished = 0;
self.queue = [[NSOperationQueue alloc] init];
self.queue.maxConcurrentOperationCount = 5;
[self.queue addObserver: self forKeyPath: #"operations" options: 0 context: NULL];
NSBlockOperation *operation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakOperation = operation;
__block NSString *response = #"";
for (int i = 0; i < imgArray.count; i++) {
operation = [NSBlockOperation blockOperationWithBlock:^{
[self uploadingPhoto];
}];
[operation setCompletionBlock:^{
NSLog(#"Operation 1-%d Completed", i);
photoFinished++;
dispatch_async(dispatch_get_main_queue(), ^{
hud.label.text = [NSString stringWithFormat: #"%d photo complete uploading", photoFinished];
});
}];
[self.queue addOperation: operation];
}
}
I want to press cancel button on MBProgressHUD to first canceled all the NSURLSessionDataTask and then cancel all operations, but didn't work.
- (void)cancelWork:(id)sender {
NSLog(#"cancelWork");
NSLog(#"self.queue.operationCount: %lu", (unsigned long)self.queue.operationCount);
[session getTasksWithCompletionHandler:^(NSArray<NSURLSessionDataTask *> * _Nonnull dataTasks, NSArray<NSURLSessionUploadTask *> * _Nonnull uploadTasks, NSArray<NSURLSessionDownloadTask *> * _Nonnull downloadTasks) {
if (!dataTasks || !dataTasks.count) {
return;
}
for (NSURLSessionDataTask *task in dataTasks) {
[task cancel];
if ([self.queue operationCount] > 0) {
[self.queue cancelAllOperations];
}
}
}];
}
I used semaphore to let NSURLSession become Synchronous connection.
- (void)uploadingPhoto {
request setting above
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.timeoutIntervalForRequest = 1200;
session = [NSURLSession sessionWithConfiguration: config];
dataTask = [session dataTaskWithRequest: request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error == nil) {
str = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"str: %#", str);
}
dispatch_semaphore_signal(semaphore);
}];
NSLog(#"task resume");
[dataTask resume];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return str;
}
Any comments or solutions will be greatly appreciated.
An NSOperation does not by default have support for cancellation. See the class documentation. One extract is:
Canceling an operation does not immediately force it to stop what it is doing. Although respecting the value in the cancelled property is expected of all operations, your code must explicitly check the value in this property and abort as needed.
It also seems hard to implement cancellation using NSBlockOperation.

Activity Indicator while calling API

I want to display the activity indicator while waiting for the API to return. The problem is after all the result I get from API, then the spinner only display. The result I want is while waiting for API call, then the spinner will running.
I'm calling this method in here
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
[self startLoadingSpinner]
//Calling API...
[self stopLoadingSpinner]
}
Here is the method for the activity indicator
-(void)startLoadingSpinner {
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 70, 70)];
self.activityIndicator.opaque = YES;
self.activityIndicator.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.4f];
self.activityIndicator.center = self.view.center;
self.activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
[self.activityIndicator setColor:[UIColor whiteColor]];
[self.view addSubview:self.activityIndicator];
[self.activityIndicator startAnimating];
}
This is how I stop the activity indicator
-(void)stopLoadingSpinner {
[self.activityIndicator performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:0.5];
}
Don't add activity indicators in tableview datasource method - numberOfRowsInSection .
Add these two functions calling in the same method where you are making an API call. Make an API call in ViewDidLoad, some life cycle method or in action methods.
Below is the example of using it.
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"http://httpbin.org/get"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
[self startLoadingSpinner]
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"Error: %#", error);
} else {
NSLog(#"%# %#", response, responseObject);
}
[self stopLoadingSpinner]
}];
[dataTask resume];
In Swift
func makeAPIRequest(to endPoint: String) {
// here you can showActivetyIndicator start progressing here
self.startLoadingSpinner()
Alamofire.request(endPoint).responseJSON{ response in
if let value = response.result.value {
let responseInJSON = JSON(value)
self._responseInJSON = responseInJSON
}
// here you can hide Your ActivetyIndicator here
self.stopLoadingSpinner()
}
}
My detailed answer is below
-(void)simpleGetResponse{
#try {
//Call the Activity Indicator show method here
[self startLoadingSpinner];
NSString *strURL = #"Your URL";
NSURL *urlStr = [NSURL URLWithString:strURL];
NSMutableURLRequest *mutaURL = [NSMutableURLRequest requestWithURL:urlStr];
[mutaURL setHTTPMethod:#"GET"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:mutaURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if(httpResponse.statusCode == 200)
{
NSError *parseError = nil;
id response = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if(response != nil){
if([response isKindOfClass:[NSDictionary class]]){
NSLog(#"response is in dictionary format %#",response);
NSDictionary *dictRes = [response copy];
NSLog(#"The dictRes is - %#",dictRes);
}
else{
NSLog(#"response is in array format %#",response);
NSDictionary *arrRes = [response copy];
NSLog(#"The arrRes is - %#",arrRes);
}
dispatch_async(dispatch_get_main_queue(), ^{
//Call the Activity Indicator hidden method inside the dispatch_main_queue method
[self stopLoadingSpinner]
[yourTableView reloadData];
});
}
}
else
{
NSLog(#"Error");
}
}];
[dataTask resume];
}
#catch (NSException *exception) {
NSLog(#"%#", [exception description]);
}
#finally {
}
}

Wait for NSURLSessionDataTask to come back

I am new to Objective C and iOS development in general. I am trying to create an app that would make an http request and display the contents on a label.
When I started testing I noticed that the label was blank even though my logs showed that I had data back. Apparently this happens because the the response is not ready when the label text gets updated.
I put a loop on the top to fix this but I am almost sure there's got to be a better way to deal with this.
ViewController.m
- (IBAction)buttonSearch:(id)sender {
HttpRequest *http = [[HttpRequest alloc] init];
[http sendRequestFromURL: #"https://en.wiktionary.org/wiki/incredible"];
//I put this here to give some time for the url session to comeback.
int count;
while (http.responseText ==nil) {
self.outputLabel.text = [NSString stringWithFormat: #"Getting data %i ", count];
}
self.outputLabel.text = http.responseText;
}
HttpRequest.h
#import <Foundation/Foundation.h>
#interface HttpRequest : NSObject
#property (strong, nonatomic) NSString *responseText;
- (void) sendRequestFromURL: (NSString *) url;
- (NSString *) getElementBetweenText: (NSString *) start andText: (NSString *) end;
#end
HttpRequest.m
#implementation HttpRequest
- (void) sendRequestFromURL: (NSString *) url {
NSURL *myURL = [NSURL URLWithString: url];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: myURL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest: request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
self.responseText = [[NSString alloc] initWithData: data
encoding: NSUTF8StringEncoding];
}];
[task resume];
}
Thanks a lot for the help :)
Update
After reading a lot for the very useful comments here I realized that I was missing the whole point. So technically the NSURLSessionDataTask will add task to a queue that will make the call asynchronously and then I have to provide that call with a block of code I want to execute when the thread generated by the task has been completed.
Duncan thanks a lot for the response and the comments in the code. That helped me a lot to understand.
So I rewrote my procedures using the information provided. Note that they are a little verbose but, I wanted it like that understand the whole concept for now. (I am declaring a code block rather than nesting them)
HttpRequest.m
- (void) sendRequestFromURL: (NSString *) url
completion:(void (^)(NSString *, NSError *))completionBlock {
NSURL *myURL = [NSURL URLWithString: url];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: myURL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest: request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//Create a block to handle the background thread in the dispatch method.
void (^runAfterCompletion)(void) = ^void (void) {
if (error) {
completionBlock (nil, error);
} else {
NSString *dataText = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
completionBlock(dataText, error);
}
};
//Dispatch the queue
dispatch_async(dispatch_get_main_queue(), runAfterCompletion);
}];
[task resume];
}
ViewController.m
- (IBAction)buttonSearch:(id)sender {
NSString *const myURL = #"https://en.wiktionary.org/wiki/incredible";
HttpRequest *http = [[HttpRequest alloc] init];
[http sendRequestFromURL: myURL
completion: ^(NSString *str, NSError *error) {
if (error) {
self.outputText.text = [error localizedDescription];
} else {
self.outputText.text = str;
}
}];
}
Please feel free to comment on my new code. Style, incorrect usage, incorrect flow; feedback is very important in this stage of learning so I can become a better developer :)
Again thanks a lot for the replies.
You know what, use AFNetworking to save your life.
Or just modify your HttpRequest's sendRequestFromURL:
- (void)sendRequestFromURL:(NSString *)url completion:(void(^)(NSString *str, NSError *error))completionBlock {
NSURL *myURL = [NSURL URLWithString: url];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: myURL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest: request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
completionBlock(nil, error);
} else {
completionBlock([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding], error);
}
});
}];
[task resume];
}
and invoke like this
[http sendRequestFromURL:#"https://en.wiktionary.org/wiki/incredible" completion:^(NSString *str, NSError *error) {
if (!error) {
self.outputLabel.text = str;
}
}];
Rewrite your sendRequestFromURL function to take a completion block:
- (void) sendRequestFromURL: (NSString *) url
completion: (void (^)(void)) completion
{
NSURL *myURL = [NSURL URLWithString: url];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: myURL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest: request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
self.responseText = [[NSString alloc] initWithData: data
encoding: NSUTF8StringEncoding];
if (completion != nil)
{
//The data task's completion block runs on a background thread
//by default, so invoke the completion handler on the main thread
//for safety
dispatch_async(dispatch_get_main_queue(), completion);
}
}];
[task resume];
}
Then, when you call sendRequestFromURL, pass in the code you want to run when the request is ready as the completion block:
[self.sendRequestFromURL: #"http://www.someURL.com&blahblahblah",
completion: ^
{
//The code that you want to run when the data task is complete, using
//self.responseText
}];
//Do NOT expect the result to be ready here. It won't be.
The code above uses a completion block with no parameters because your code saved the response text to an instance variable. It would be more typical to pass the response data and the NSError as parameters to the completion block. See #Yahoho's answer for a version of sendRequestFromURL that takes a completion block with a result string and an NSError parameter).
(Note: I wrote the code above in the SO post editor. It probably has a few syntax errors, but it's intended as a guide, not code you can copy/paste into place. Objective-C block syntax is kinda nasty and I usually get it wrong the first time at least half the time.)
If you want easy way then Don't make separate class for call webservice. Just make meethod in viewController.m instead. I mean write sendRequestFromURL in your viewController.m and update your label's text in completion handler something like,
- (void) sendRequestFromURL: (NSString *) url {
NSURL *myURL = [NSURL URLWithString: url];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: myURL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest: request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
self.responseText = [[NSString alloc] initWithData: data
encoding: NSUTF8StringEncoding];
self.outputLabel.text = self.responseText;
})
}];
[task resume];
}

Make periodic server requests with NSURLSessionDataTask and dispatch_source timer

Need some help and explanation, because i'm really stuck in my question. i need to make this:
1) I make one request to the server, get some response and then i want to make another request every 7 seconds(example). also get some response. if it satisfy several conditions -> stop timer and do some stuff.
Main problem is that timer never stops, despite the fact that all in all i get response right. i assume that i use GCD incorrectly. because in debug this code behaves really strange.
What i have done:
This is my request function(it became like this after i read about 50 links how to do similar things)
-(void)makeRequestWithURL:(NSString*)urlString andParams:(NSString*)params andCompletionHandler:(void(^)(NSDictionary *responseData, NSError *error))completionHnadler{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
request.HTTPMethod = #"POST";
request.HTTPBody = [params dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (completionHnadler) {
if (error) {
dispatch_async(dispatch_get_main_queue(), ^{
completionHnadler(nil, error);
});
} else {
NSError *parseError;
json = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:&parseError];
dispatch_async(dispatch_get_main_queue(), ^{
completionHnadler(json, parseError);
});
}
}
}];
[postDataTask resume]; }
I create my timer like this:
dispatch_source_t CreateDispatchTimer(uint64_t interval,
uint64_t leeway,
dispatch_queue_t queue ,
dispatch_block_t block) {
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer) {
// Use dispatch_time instead of dispatch_walltime if the interval is small
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
dispatch_source_set_event_handler(timer, block);
dispatch_resume(timer);
}
return timer; }
and called it like this:
-(void)checkForPassenger {
timerSource = CreateDispatchTimer(7ull * NSEC_PER_SEC, 1ull * NSEC_PER_SEC, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if([self getNotificationsRequest] == YES) {
dispatch_source_cancel(timerSource);
} else {
NSLog(#"go on timer");
}
NSLog(#"Driver checked for passenger!");
}); }
this is the code of periodic response:
-(BOOL)getNotificationsRequest {
NSString *urlString = #"http://primetime.by/temproad/do";
NSString *params = [NSString stringWithFormat:#"event={\"type\": \"in.getNotifications\"}&session_id=%#",session_id];
[self makeRequestWithURL:urlString andParams:params andCompletionHandler:^(NSDictionary *responseData, NSError *error) {
if ([[responseData objectForKey:#"rc"] intValue] == 0) {
NSArray *temp_notifications = [responseData objectForKey:#"notifications"];
if (temp_notifications.count != 0) {
notification = [[Notification alloc] initWithNotification:[[responseData objectForKey:#"notifications"] objectAtIndex:0]];
}
}
}];
if (notification) {
return YES;
} else {
return NO;
} }
and this is what i do in main request:
[self makeRequestWithURL:urlString andParams:params andCompletionHandler:^(NSDictionary *responseData, NSError *error) {
if ([[responseData objectForKey:#"rc"] intValue] == 0) {
route = [[Route alloc] initWithData:responseData];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self checkForPassenger];
});
}
}];
NSLog(#"bye");
maybe explanation is bad so i can answer any question.
thx

UITableView cell shows same images on fast scrolling

I am creating the iPhone app which shows the app icons & app names in table view.
First time i download the images in user document directory & then make entry in dictionary [value - image stored document directory path & key is image json URL], for showing image in cell first i checked the image is already download or not.
If downloaded, then show the local image which stored on document directory and if not download it.
If i Scrolled normally, cell shows the rights images & if i scrolled it fast, cell shows the same images instead of different.
// code for displaying images
-(void)refreshViews
{
self.appLabelName.text = _applicationObject.name;
self.appLabelName.font = [UIFont fontWithName:#"Helvetica-Bold" size:17];
self.detailTextLabel.text = _applicationObject.artistName;
self.detailTextLabel.font = [UIFont fontWithName:#"Helvetica" size:14];
NSString *appIconStoredPath = [appDelgate.saveAppIconURLAndPathInFile valueForKey:_applicationObject.iconURL];
_appIcon.image = [UIImage imageWithContentsOfFile:appIconStoredPath];
if(!_appIcon.image && appDelgate.hasInternetConnection)
{
[self downloadAppIconsInDirectory];
}
}
// code for download image
-(void)downloadAppIconsInDirectory
{
NSURL *downloadURL = [NSURL URLWithString:_applicationObject.iconURL];
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:nil delegateQueue:nil];
__weak ApplicationCell* weakSelf = self;
dispatch_async(queue, ^{
downloadTask = [session downloadTaskWithURL:downloadURL completionHandler:^(NSURL *location, NSURLResponse *respone, NSError *error)
{
NSString *iconName = [location lastPathComponent];
NSMutableString *changeIconName = [[NSMutableString alloc] init];
changeIconName = [iconName mutableCopy];
[changeIconName setString:_applicationObject.bundleId];![enter image description here][1]
NSString *appIconDirectory = [[documentsDirectoryForAppIcons absoluteString] stringByAppendingPathComponent:#"appIcons"];
destinationUrlForAppIcons = [[NSURL URLWithString:appIconDirectory] URLByAppendingPathComponent:changeIconName];
NSError *error1;
BOOL status = [appIconFileManager copyItemAtURL:location toURL:destinationUrlForAppIcons error:&error1];
if (status && !error1)
{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf refreshViews];
});
[appDelgate.saveAppIconURLAndPathInFile setValue:destinationUrlForAppIcons.path forKey:_applicationObject.iconURL];
NSString *dictSavedFilePath = [appDelgate.documentDirectoryPath stringByAppendingPathComponent:#"IconURLsAndPaths.plist"];
dispatch_async(queue, ^{
[appDelgate.saveAppIconURLAndPathInFile writeToFile:dictSavedFilePath atomically:YES];
});
}
}];
[downloadTask resume];
});
}
As it shows, there is no error in code. This means you are priority for queues is wrong. Image must be downloaded before scrolling. As you scroll your view slow, image gets enough time to be downloaded. This means you change your code to this and try ;)
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration
defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:nil
delegateQueue:nil];
__weak ApplicationCell* weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
downloadTask = [session downloadTaskWithURL:downloadURL completionHandler:^(NSURL *location,
{
NSString *iconName = [location lastPathComponent];
NSMutableString *changeIconName = [[NSMutableString alloc] init];
changeIconName = [iconName mutableCopy];
[changeIconName setString:_applicationObject.bundleId];![enter image description here]
[1]
NSString *appIconDirectory = [[documentsDirectoryForAppIcons absoluteString]
stringByAppendingPathComponent:#"appIcons"];
destinationUrlForAppIcons = [[NSURL URLWithString:appIconDirectory]
URLByAppendingPathComponent:changeIconName];
NSError *error1;
BOOL status = [appIconFileManager copyItemAtURL:location
toURL:destinationUrlForAppIcons error:&error1];
if (status && !error1)
{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf refreshViews];
});
[appDelgate.saveAppIconURLAndPathInFile
setValue:destinationUrlForAppIcons.path forKey:_applicationObject.iconURL];
NSString *dictSavedFilePath = [appDelgate.documentDirectoryPath
stringByAppendingPathComponent:#"IconURLsAndPaths.plist"];
dispatch_async(queue, ^{
[appDelgate.saveAppIconURLAndPathInFile writeToFile:dictSavedFilePath
atomically:YES];
});
}
}];
[downloadTask resume];
});
}
replace your refreshViews method with this
-(void)refreshViews
{
self.appLabelName.text = _applicationObject.name;
self.appLabelName.font = [UIFont fontWithName:#"Helvetica-Bold" size:17];
self.detailTextLabel.text = _applicationObject.artistName;
self.detailTextLabel.font = [UIFont fontWithName:#"Helvetica" size:14];
_appIcon.image = nil;
NSString *appIconStoredPath = [appDelgate.saveAppIconURLAndPathInFile valueForKey:_applicationObject.iconURL];
_appIcon.image = [UIImage imageWithContentsOfFile:appIconStoredPath];
if(!_appIcon.image && appDelgate.hasInternetConnection)
{
[self downloadAppIconsInDirectory];
}
}
Its load previous image because your tableview reuse the cell so the imageview also reusing which hold the previous image. so you have to do nil this image

Resources